Планировщик задач WCF или таймер, как в OGame, Travian и т. Д. - PullRequest
0 голосов
/ 07 мая 2011

Я ищу ресурсы или тех, у кого есть планировщик записи в 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 из Entity Framework, я могу добавить задачи от нескольких клиентов, и они будут добавлены в БД в порядке от newset до самого старого (или от самого короткого до самого длинного?).

Дело в том, что пользователь CANT может отслеживать свои задачи. Когда я меняю страницу, я не вижу, сколько времени осталось до выполнения задачи. Этот код по сути не обеспечивает отслеживание времени, потому что я избавился от него, так как он все равно не работал.

Полагаю, я должен хранить свою задачу в каком-то главном хранилище данных, и каждый раз, когда пользователь проверяет состояние новой страницы, проверяемое из этого хранилища, следует отправлять ему.

Я не эксперт, но я думаю, что лучший вариант здесь - хранить все данные в памяти, пока задача не будет выполнена. Любая реляционная база данных, вероятно, будет работать медленно, если мне придется постоянно обновлять записи с заданным состоянием задачи.

Я знаю, что должен просто синхронизировать таймер на стороне клиента с сервером и не передавать потоковое время с сервера. Но здесь возникает большой вопрос, как получить новое состояние задачи, когда пользователь возвращается на страницу через 3 секунды или 3 часа?

Любые советы, как заставить его работать как положено.

И, кстати. Я использую pollingduplex и Silverlight.

1 Ответ

1 голос
/ 07 мая 2011

Звучит так, как будто вы используете 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он предназначен для работы во времени.Он хранит данные в состоянии, пока что-то не изменится (независимо от времени), не потребляя лишних ресурсов.Кроме того, он допускает постоянство и параллельные процессы.

...