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

发布于 2024-11-05 19:54:35 字数 4364 浏览 2 评论 0 原文

我正在寻找资源,或者任何在 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();
    }

我已经对大多数值进行了硬编码,以进行测试。

InstanceContextMode 是为 PerCall 设置的。

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

关键是,用户无法跟踪他的任务。当我更改页面时,我看不到任务完成还剩多少时间。该代码本质上不提供时间跟踪,因为我摆脱了它,因为它无论如何都不起作用。

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

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

我知道我应该只将客户端计时器与服务器同步,而不是从服务器持续传输时间。但最大的问题是,当用户 3 秒或 3 小时后返回页面时,如何获取任务进度的新集状态?

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

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

I'm looking for resources, or anyone who have writting scheduler in WCF.
What I want to achive is basically what can you see in OGame, or Travian or doznes of other text browser based game.

Player click and send task to server to make building for him, or unit or something else.
From what I figured out I need to run some kind if scheduler on server that will gather all tasks, and will track them, until some perdiod of time will pass (2 mins, 10 mins, 3 days etc.), and after that period end service should call an action, like send data to database.

Well. I've been trying to make something very simply, that I can start from and ended with this:

    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();
    }

I have hardcoded most values, for testing.

InstanceContextMode is set for PerCall.

Anyway. This code is working. At least to some point. If we ignore zylion exceptions from Entity Framework, I can add tasks from multiple clients and they are added to db in order from newset to oldest (or shortest to longest ?).

The point is, user CANT track his tasks. When I change page I don't see how much time remaining till task done. This code essentialy do not provide time tracking because i got rid of it as it wasn't working anyway.

I guess I should store my task in some presitant data storage and everytime user check page newset state should be draw from that storage and send to him.

I'm not and expert but i think best option here is to store all data in Memory until task is done.
Any relational database will be probably to slow, if I will have to constantly update records with newset state of task.

I know I should just synchronize client side timer with server and do not stream constatly time from server. But Big question is here how to get newset state of task pogress when user come back to page after 3 second or 3 hours ?

Any advices how to make it work as expected.

And btw. I'm using pollingduplex and Silverlight.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

青萝楚歌 2024-11-12 19:54:35

听起来您正在使用 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 服务,并且它被设计为随着时间的推移而工作。它将数据保存在状态中,直到发生变化(无论时间长短),而不会消耗过多的资源。此外,它还允许持久性和并行进程。

It sounds like you are using WCF to do something for which it wasn't designed (but I understand the need). I would suggest you look at Workflow Foundation (WF) as a possible solution to your problem. Here is a good explanation:

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

Here is also a good intro video:

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

Workflow can consume WCF services and it is designed to work over time. It holds data in state until something changes (regardless of time) without consuming excess resources. Also, it allows for persistance and parallel processes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文