WCF任务调度程序,或者像OGame,Travian等中的计时器

时间:2011-05-07 17:08:56

标签: c# wcf scheduled-tasks scheduling

我正在寻找资源,或者在WCF中拥有写入调度程序的任何人。 我想要实现的基本上是你能在OGame,Travian或其他基于文本浏览器的游戏中看到的东西。

玩家点击并向服务器发送任务,为他或单位或其他东西建造。 根据我的想法,我需要运行某种类型,如果服务器上的调度程序将收集所有任务,并将跟踪它们,直到一段时间过去(2分钟,10分钟,3天等),并在此期间之后终端服务应该调用一个动作,比如将数据发送到数据库。

好。我一直在努力做一些非常简单的事情,我可以从这开始并以此结束:

    public class BuildingScheduler
{
    public int TaskID { get; set; }
    public string UserName { get; set; }
    public DateTime TaskEnd { get; set; }
    public string BuildingName { get; set; }
    public bool TaskDone { get; set; }
    public DateTime RemainingTime { get; set; }
    TestDBModelContainer _ctx;
    TestData _testData;

    public IDuplexClient Client { get; set; }

    public BuildingScheduler()
    {
        TaskDone = false;
    }

    public void MakeBuilding()
    {
        while (DateTime.Now <= TaskEnd)
        {
            //Client.DisplayMessage(DateTime.Now.ToString());
            RemainingTime = DateTime.Now;
        }
        _testData = new TestData { DataName = BuildingName, Created = DateTime.Now };
        _ctx = new TestDBModelContainer();
        _ctx.TestDataSet.AddObject(_testData);
        _ctx.SaveChanges();
        TaskDone = true;
        //Client.DisplayMessage("Building completed!");
    }
}

static List<UserChannel> _userChannels = new List<UserChannel>();

    static List<BuildingScheduler> _buildingSchedules = new List<BuildingScheduler>();
    List<BuildingScheduler> _buildingSchedulesToRemove = new List<BuildingScheduler>();

    [OperationContract]
    public void DoWork()
    {
        IDuplexClient client = OperationContext.Current.GetCallbackChannel<IDuplexClient>();
        UserChannel userChannel = new UserChannel { Client = client, ClientName = "TestClient" };
        string clientName = (from p in _userChannels
                             where p.ClientName == "TestClient"
                             select p.ClientName).FirstOrDefault();

        lock (((ICollection)_userChannels).SyncRoot)
        {
            if (clientName == null)
            {
                _userChannels.Add(userChannel);
            }
        }
        CheckBuilding();
    }

    private void CheckBuilding()
    {
        BuildingScheduler bs = (from p in _buildingSchedules
                                where p.UserName == "TestClient"
                                select p).FirstOrDefault();
        IDuplexClient client = (from p in _userChannels
                                where p.ClientName == "TestClient"
                                select p.Client).FirstOrDefault();
        if (bs != null)
        {
            client.DisplayMessage(bs.RemainingTime);
        }
    }

    private void StartBuilding()
    {
        foreach (BuildingScheduler bs in _buildingSchedules)
        {
            if (bs.TaskDone == false)
            {
                bs.MakeBuilding();
            }
            else if (bs.TaskDone == true)
            {
                _buildingSchedulesToRemove.Add(bs);
            }
        }

        for(int i = 0; i <= _buildingSchedulesToRemove.Count; i++)
        {
            BuildingScheduler bs = _buildingSchedulesToRemove.Where(p => p.TaskDone == true).Select(x => x).FirstOrDefault();
            _buildingSchedules.Remove(bs);
            _buildingSchedulesToRemove.Remove(bs);
        }

        CheckBuilding();
    }

    [OperationContract]
    public void MakeBuilding(string name)
    {

        BuildingScheduler _buildng = new BuildingScheduler();


        //_buildng.Client = client;
        _buildng.TaskID = 1;
        _buildng.UserName = "TestClient";
        _buildng.TaskEnd = DateTime.Now.AddSeconds(50);
        _buildng.BuildingName = name;

        _buildingSchedules.Add(_buildng);
        StartBuilding();
    }

我已经硬编码了大多数值,用于测试。

为PerCall设置了InstanceContextMode。

反正。这段代码正在运行。至少在某种程度上。如果我们忽略来自Entity Framework的zylion异常,我可以从多个客户端添加任务,并按照从newset到最旧(或从最短到最长?)的顺序将它们添加到db。

关键是,用户CANT跟踪他的任务。当我改变页面时,我看不到任务完成剩余的时间。这段代码本质上不提供时间跟踪,因为我摆脱它,因为它无论如何都没有。

我想我应该将我的任务存储在一些预先存储的数据存储中,并且每次用户检查页面都应该从该存储中抽取新的状态并发送给他。

我不是专家,但我认为这里的最佳选择是将所有数据存储在内存中,直到任务完成。 如果我必须不断更新具有newset任务状态的记录,任何关系数据库都可能会变慢。

我知道我应该只将客户端计时器与服务器同步,并且不要从服务器传输持续时间。但是,当用户在3秒或3小时后回到页面时,如何获得新的任务进度状态这里有一个很大的问题?

任何建议如何使其按预期工作。

顺便说一下。我正在使用pollingduplex和Silverlight。

1 个答案:

答案 0 :(得分:1)

听起来你正在使用WCF来做一些它没有设计的东西(但我明白需要)。我建议您查看Workflow Foundation(WF)作为您问题的可能解决方案。这是一个很好的解释:

http://msdn.microsoft.com/library/dd851337.aspx

这也是一个很好的介绍视频:

http://channel9.msdn.com/Blogs/mwink/Introduction-to-Workflow-Services-building-WCF-Services-with-WF

工作流可以使用WCF服务,它可以随着时间的推移而运行。它保持状态数据直到某些变化(无论时间如何)而不消耗过多的资源。此外,它允许持久性和并行过程。