数据迁移到Service Fabric状态服务

时间:2018-05-21 01:59:41

标签: .net-core service-fabric-stateful azure-service-fabric

我有一个有状态的服务,它存储了一大堆关于我的用户的数据,这些数据存储在一个可靠的字典中,显然也从那里检索它。

但是,我还有一个使用来存储此信息的SQL数据库。在初始化新的有状态服务实例时,我需要将该信息从我的SQL数据库迁移到新的可靠存储机制中。从那时起,有状态的服务就是真理的源泉。理想情况下,我希望延迟有状态服务的可用性,直到初始化过程完成。

对于如何做到这一点的方法有什么建议吗?

2 个答案:

答案 0 :(得分:1)

我不确定我是否帮助你。但根据您的评论,我建议以下解决方案在迁移过程中返回“未就绪”响应。

public interface IMigrationService
{
    bool IsDone();
}

public class MigrationService : IMigrationService
{
    private bool migrating = tu;

    public bool BeginMigration()
    {
        this.migrating = true;
    }
    public bool EndMigration()
    {
        this.migrating = false;
    }
    public bool IsDone()
    {
        return this.migrating;
    }
}

// WebHost startup class
public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        // Register a middle-ware that would short circuit responses
        // while migration is in progress.
        app.Use(
            async (context, next) =>
            {
                var migrationService = 
                    context.RequestServices.GetService<IMigrationService>();
                if (!migrationService.IsDone())
                {
                    /* short circuit the response with approriate error message */
                }

                await next();
            });

        app.UseMvc();
    }
}

public class Stateful : StatefulService
{
    private readonly IMigrationService migrationService;

    public Stateful(StatefulServiceContext context)
      : base(context)
    { 
        this.migrationService = new MigrationService();
    }

    protected override IEnumerable<ServiceReplicaListener>
        CreateServiceReplicaListeners()
    {
        /* 
            Create a listener here with WebHostBuilder

            Use Startup class with the middle-ware defined and 
            add configure services -> .ConfigureServices() 
            with services.AddSingleton<IMigrationService>(this.migrationService)
        */
    }

    protected override async Task 
        RunAsync(CancellationToken cancellationToken)
    {
        this.migrationService.StartMigration();

        /* Migration code */

        this.migrationService.EndMigration();
    }
}

这将允许您推出新版本的服务,该版本会在迁移过程中使用适当的错误消息将所有请求短路。

希望这有帮助。

答案 1 :(得分:0)

类似的事情可以解决问题:

public interface IStateful1 : IService
{
    Task MyMethod();
}

internal sealed class Stateful1 : StatefulService, IStateful1
{
    private bool isReady = false; 

    public Stateful1(StatefulServiceContext context)
        : base(context)
    { }

    public Task MyMethod()
    {
        if(!isReady)
            throw new NotImplementedException(); // Probably throw or return something more meaningful :-) 

        return Task.CompletedTask; // Do your thing here
    }

    protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
    {
        return new ServiceReplicaListener[0];
    }

    protected override async Task RunAsync(CancellationToken cancellationToken)
    {
        await Task.Run(() => {
            // Simulation of some work
            Thread.Sleep((int)TimeSpan.FromMinutes(5).TotalMilliseconds);
        });

        isReady = true;
    }
}  

在此设置中,从DB导入可靠集合是在RunAsync方法中完成的。

不幸的是,AFAIK,以后无法插入通信监听器。这会让事情变得更容易。

如果CreateServiceReplicaListeners是异步操作,我们可以在这里等待初始化任务,但我们现在不能。使用.Wait()不会起作用,因为它会报告该实例需要很长时间才能运行并将该实例标记为不健康。

可以在the docs

中找到服务生命周期的完整概述