Saltar al contenido principal

DNN · IScheduledTask

DNN ejecuta tareas planificadas con su Scheduler nativo. Una clase que herede de SchedulerClient (espacio DotNetNuke.Services.Scheduling) entra automáticamente en la lista al registrar el assembly y se ejecuta según la frecuencia que tú definas en Host → Schedule.

Schedulers/NeuroonSyncScheduler.cs

using System;
using System.Collections.Generic;
using DotNetNuke.Instrumentation;
using DotNetNuke.Services.Scheduling;

public class NeuroonSyncScheduler : SchedulerClient
{
private static readonly ILog Logger = LoggerSource.Instance.GetLogger(typeof(NeuroonSyncScheduler));

public NeuroonSyncScheduler(ScheduleHistoryItem oItem) : base()
{
ScheduleHistoryItem = oItem;
}

public override void DoWork()
{
try
{
Progressing();

var client = new NeuroonClient();
var products = LoadProductsFromCommerceModule();

var mode = ScheduleHistoryItem.ScheduleSource == ScheduleSource.STARTED_FROM_BEGIN_REQUEST
? NeuroonClient.SyncMode.FULL
: NeuroonClient.SyncMode.INCREMENTAL;

var result = client.SyncProductsAsync(mode, products).GetAwaiter().GetResult();

ScheduleHistoryItem.AddLogNote(
$"Mode: {mode}. " +
$"Synced {result.NewProducts} new, {result.UpdatedProducts} updated, " +
$"{result.Failed} failed. Quota {result.ProductsCount}/{result.ProductsCount + result.RemainingProducts}.");

if (result.Failed > 0)
{
foreach (var err in result.Errors)
{
ScheduleHistoryItem.AddLogNote($"FAIL externalId={err.ExternalId}: {err.Error}");
}
}

ScheduleHistoryItem.Succeeded = true;
Logger.Info($"Neuroon sync OK ({result.NewProducts}+{result.UpdatedProducts})");
}
catch (Exception ex)
{
ScheduleHistoryItem.Succeeded = false;
ScheduleHistoryItem.AddLogNote("Neuroon sync failed: " + ex.Message);
Logger.Error("Neuroon sync failed", ex);
Errored(ref ex);
}
}

private static IEnumerable<NeuroonProduct> LoadProductsFromCommerceModule()
{
// Adapta a tu módulo de e-commerce.
// Ejemplo NB_Store:
// foreach (var p in NBrightBuy.GetActiveProducts(portalId))
// yield return ProductMapper.Map(p);
throw new NotImplementedException("Implementa el mapeo desde tu módulo de e-commerce.");
}
}

Registrar el scheduler

  1. Compila el assembly que contiene NeuroonSyncScheduler y despliégalo en bin/.

  2. Entra a Host → Schedule → Add Item:

    CampoValor recomendado
    Friendly nameNeuroon Product Sync
    TypeFull type name → NeuroonSyncScheduler, MyAssembly
    Schedule1 day
    Catch-up EnabledYes
    Retain history30 entries
    Run on eventNone
    Servers(vacío = todos)
  3. Pulsa UpdateRun Now para validar la primera ejecución.

Cita: configuración del scheduler en el recipe DNN end-to-end (Paso 4).

Sync delta horaria (opcional)

Para reducir el lag entre edición de producto y aparición en Neuroon, registra un segundo scheduler con frecuencia 1 hour que filtre por LastUpdatedDate > UtcNow.AddHours(-1):

private static IEnumerable<NeuroonProduct> LoadDeltaProducts()
{
var since = DateTime.UtcNow.AddHours(-1);
return CommerceRepository
.GetProducts()
.Where(p => p.LastUpdatedDate > since)
.Select(ProductMapper.Map);
}

La sync sigue siendo INCREMENTAL. Los productos sin cambios en la última hora no se mandan.

Log notes en ScheduleHistoryItem

AddLogNote escribe entradas que se ven en Host → Schedule → History. Buenas prácticas:

  • Una línea por evento de alto nivel (modo, contadores agregados, cuota).
  • Una línea por error individual (top 20, no más, para no inflar la tabla).
  • No loguear nunca la API Key.
  • Para incidentes de larga cola, complementa con LoggerSource.Instance.GetLogger (DNN Log4Net).

Forzar FULL desde la UI

ScheduleHistoryItem.ScheduleSource indica cómo se disparó la tarea. Puedes hacer:

  • STARTED_FROM_BEGIN_REQUEST (manual, Run Now) → FULL.
  • STARTED_FROM_SCHEDULER (cron) → INCREMENTAL.

Esto evita que el job nocturno marque productos como inactivos por accidente, y permite forzar un re-bootstrap completo desde la UI.

Diagnóstico de tareas paradas

Si la tarea queda Stuck en Running:

  1. Comprueba que Errored(ref ex) se invoca en cada catch.
  2. Mira wp-content/Logs/SchedulingErrorXX.log (en DNN, Portals/_default/Logs/).
  3. Reduce el batch o aumenta el timeout del HttpClient.

Próximos pasos