线程定时器不回调 [英] Threading Timer doesn't callback

查看:94
本文介绍了线程定时器不回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有哪些国家有几台机器类无论是在线/离线和DateTime EndsAt当他们他们是否在线离线会转。他们使用的是EF(映射?)到数据库中。当我打开它们我通过数秒,让他们保持在线,并创建System.Threading.Timer在时机成熟时,以改变其状态恢复到离线(EndsAt == DateTime.Now)。谈到他们的精品工程,但他们不要关闭 - 倒胃口()不会被调用。而最重要的是它是否会被调用的对象会改变它自己的变量他们将被实体框架得救了吗?

 公共类机
{
    私人定时器定时= NULL;
    [键]
    公众诠释设备ID {搞定;组; }
    公共BOOL在线{搞定;组; }
    公众的DateTime EndsAt {搞定;组; }    公共无效TurnOn(时间跨度量)
    {
        的Debug.WriteLine(打开达);
        如果(!在线)
        {
            EndsAt = DateTime.Today.Add(量);
            在线= TRUE;
            SetTimer的();
        }
    }    私人无效倒胃口(对象状态)
    {
        在线= FALSE;
        Occuppied = FALSE;
        的Debug.WriteLine(计时器结束!);
    }    私人无效SetTimer的()
    {
        的Debug.WriteLine(计时器被设置);
        如果(EndsAt.CompareTo(DateTime.Now)== 1)
        {
            定时器=新定时器(新TimerCallback(关断));
            INT msUntilTime =(INT)((EndsAt - DateTime.Now).TotalMilliseconds);
            timer.Change(msUntilTime,Timeout.Infinite);
        }
        其他
        {
            的Debug.WriteLine(EndsAt比当前日期小);
        }
    }
}

控制器方法,其中turnOn()被调用

  [HttpPost]
    公众的ActionResult TurnOn(){
        布尔isChanged = FALSE;
        如果(请求[机号] = NULL&放大器;!&安培;!请求[数量] = NULL)
        {
            字节=设备ID Convert.ToByte(请求[机号]的ToString());
            INT金额= Convert.ToInt32(请求[数量]的ToString());            的foreach(VAR机db.Machines.ToList())
            {
                如果(machine.MachineId ==设备ID)
                {
                    machine.TurnOn(TimeSpan.FromSeconds(量));
                    db.Entry(机).STATE = EntityState.Modified;
                    db.SaveChanges();
                    isChanged = TRUE;
                }
            }
        }
        如果(isChanged)
            返回新的HTTPStatus codeResult(的HTTPStatus code.OK);
        其他
            返回新的HTTPStatus codeResult(的HTTPStatus code.BadRequest);
    }


解决方案

这个问题从实体框架,但ASP.NET来没有。

我可以形容,那就是在想象你的ASP.NET页面请求是一个控制台应用程序,应用程序启动时为每个新请求,确实请求和响应用户,最好的方法等待一点点的另一个请求来在随后退出的Main()功能。

如果您创建该类型的应用程序定时器一旦点点耗尽和的Main()返回您的计时器将不再和东西运行你在哪里等待发生绝不会发生。 IIS做这个确切的过程,但它确实有它的AppDomain的回收,如果没有请求到来时它会关闭的AppDomain,并会杀死你的计时器。

有两种方法,我知道的来处理这个问题:

第一种方法是你需要运行IIS作为是始终运行之外的Windows服务应用第二,它会是怎样保持计时器。当你想运行任何类型的长时间运行的操作时,计时器完成任一服务执行任何操作,将活得比你使用WCF一个页面请求或一些其他的技术为您的Web应用程序与服务进行通信来启动计时器,你希望他们干。

做的第二种方法是在保存定时请求在数据库中,然后在后台之前,每个请求你检查事件的数据库,看看是否要执行任何需要。还有像图书馆迟发型,使这个过程变得轻松,他们也有技巧,以保持应用程序域活得更长或唤醒回,如果它关闭的(通常使用两个网站互相沟通各自保持其他人活着)。

I have several Machine classes which have state whether they are online/offline and DateTime EndsAt when they will turn offline if they are online. They are (mapped?) to database using EF. When i turn them on i pass amount of seconds for them to stay online and create System.Threading.Timer to change its state back to offline when the time comes (EndsAt == DateTime.Now). Turning them on works fine, however they don't turn off - turnoff() is never called. And on top of that if it would be called and object would change its own variables will they be saved by entity framework?

public class Machine
{
    private Timer timer=null;
    [Key]
    public int MachineId { get; set; }
    public bool Online { get; set; }
    public DateTime EndsAt { get; set; }

    public void TurnOn(TimeSpan amount)
    {
        Debug.WriteLine("Turn on reached");
        if (!Online)
        {
            EndsAt = DateTime.Today.Add(amount);
            Online = true;
            setTimer();
        }
    }

    private void turnOff(object state)
    {
        Online = false;
        Occuppied = false;
        Debug.WriteLine("Timer ended!");
    }

    private void setTimer()
    {
        Debug.WriteLine("Timer being set");
        if (EndsAt.CompareTo(DateTime.Now) == 1)
        {
            timer = new Timer(new TimerCallback(turnOff));
            int msUntilTime = (int)((EndsAt - DateTime.Now).TotalMilliseconds);
            timer.Change(msUntilTime, Timeout.Infinite);
        }
        else
        {
            Debug.WriteLine("EndsAt is smaller than current date");
        }
    }
}

Controller method where turnOn() is called

 [HttpPost]
    public ActionResult TurnOn() {
        bool isChanged = false;
        if (Request["machineId"] != null && Request["amount"] != null)
        {
            byte machineId = Convert.ToByte(Request["machineId"].ToString());
            int amount = Convert.ToInt32(Request["amount"].ToString());

            foreach (var machine in db.Machines.ToList())
            {
                if (machine.MachineId == machineId)
                {
                    machine.TurnOn(TimeSpan.FromSeconds(amount));
                    db.Entry(machine).State = EntityState.Modified;
                    db.SaveChanges();
                    isChanged = true;
                }
            }
        }
        if (isChanged)
            return new HttpStatusCodeResult(HttpStatusCode.OK);
        else
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }

解决方案

The problem comes not from Entity Framework but ASP.NET.

The best way I can describe it is imagine your page request in ASP.NET is a console application, every new request the application starts up, does the request and responds to the user, waits a tiny bit for another request to come in then exits the Main() function.

If you created a Timer in that kind of application once the "tiny bit" runs out and the Main() returns your timer will not be running anymore and the thing you where waiting to happen will never happen. IIS does this exact process but it does it with AppDomain recycling, if no requests come in it will shut down the AppDomain and will kill your timer.

There two ways I know of to handle this problem:

The first way is you need to make a 2nd application that runs as a windows service outside of IIS that is always running, it will be what holds the timer. When you want to run any kind of long running operation that will outlive a page request you use WCF or some other technology for your web app to communicate with the service to start up the timer, when the timer is done either the service executes whatever operation you wanted done.

The second way to do it is you save the timer request in a database then in the background before every request you check the database of events and see if any need to be executed. There are libraries like hangfire that make this process easy, they also have tricks to keep the app domain alive longer or wake it back up if it shuts down (often they use two websites that talk to each other each keeping the other one alive).

这篇关于线程定时器不回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆