0

我正在编写一个 Windows 服务,它将执行不同的数据导入逻辑,从不同的数据源最终将其写入单个目标,即 MS CRM 实例。现在,我认为唯一有问题的是写给 CRM 的部分。从不同(有时是相同的)数据源同时读取数据应该不是问题(我可能错了......)所以我想出了一种方法来确保没有并发写入(创建或更新) 到 CRM。

这是目前的总体设计:

服务启动时会发生什么:

Timers = new List<System.Timers.Timer>();
CrmTransactionQueue.Lock = new object { }; //Static class. The object for locking purposes...
System.Threading.Thread.Sleep(20000); //for debugging purpose so I can attach to process before everything kicks in...

//retrieve all types that are extending BaseSyncStrategy..
var strategyTypes = Assembly.GetExecutingAssembly().GetTypes().Where(x => x.BaseType == typeof(BaseSyncStrategy));


foreach (Type strategyType in strategyTypes)
{
    //create a instance of that type....
    var strategy = (BaseSyncStrategy)Activator.CreateInstance(strategyType);

    //create a timer for each of these, they will have different intervals...
    System.Timers.Timer t = new System.Timers.Timer
    {
        Interval = strategy.Interval * 1000,
        AutoReset = false,
        Enabled = true
     };

     Timers.Add(t);

     t.Elapsed += (sender, e) => TimerElapsed(sender, e, strategy);
     t.Start();
 }

当计时器的时间间隔到期时会发生什么:

private void TimerElapsed(object sender, ElapsedEventArgs e, BaseSyncStrategy strategy)
{
    //get timer back
    var timer = (Timer)sender;

    try
    {
        strategy.Execute();
    }
    catch (Exception ex)
    {
        Logger.WriteEntry(EventLogEntryType.Error, $"Error executing strategy {strategy.GetType().Name}: ", ex);
    }

    timer.Start();
}

Execute在对象扩展的所有方法中BaseSyncStrategy,每次我想在目标 CRM 实例中更新或创建某些东西时,我都会这样做:

XrmServiceContext XrmCtx = new XrmServiceContext();

//....
//code that fetches data from foreign sources and creates CRM entities...
//....

Action<XrmServiceContext> action = (XrmServiceContext ctx) =>
{
    //write those created/updated objects
    //ctx lets me query entities and write back to CRM...
};

CrmTransactionQueue.Execute(action, XrmCtx);

以及确保(我认为)没有并发写入 CRM 的简单代码:

public static class CrmTransactionQueue
{
    public static object Lock { get; set; }

    public static void Execute(Action<XrmServiceContext> transaction, XrmServiceContext Ctx)
    {
        lock (Lock)
        {
            transaction.Invoke(Ctx);
        }
    }

}

这是声音设计还是有更好的方法来做到这一点?

4

0 回答 0