3

在 MVC3 Webapp 中安排任务时,我需要您的建议。

我的任务是为 webapp 中的不同服务创建一些通用调度程序,以便以后在开发中使用。例如,我们有一些可用的任务,用户可以随时安排。

我不想重新发明轮子,并找到了可用于创建调度程序的 Quartz.Net 库。

我知道在 webapp 中托管调度不是一个好主意,因为 webserver 可以回收应用程序池等,所以我决定在 Windows 服务中使用它,然后使用 Quartz.NET 远程处理功能在我的 webapp 中触发任务。

但我发现了一些问题。如果我错了,请纠正我,但是当我尝试使用 Quartz.NET 远程处理时,它会在 Windows 服务进程中运行该作业,这意味着它需要了解我的 webapp 中的所有类型,因此 webapp 的所有程序集应该被它引用,我需要另一个数据库配置文件等。所以如果我写新的作业类,我不能轻易安排它,我需要停止服务并为它更新库,所以这不是很通用的方法。

我找不到 Quartz.NET 只能基于其接口运行作业的任何信息。

所以我想出了编写自己的调度程序的想法,它将托管在 Windows 服务中,并且将具有一些将在 webapp 中实现的 IJob 接口。我还将通过 IPC 通道使用 .Net 远程处理。所以 webapp 就像 .Net Remoting Server,当我想添加一些新作业然后安排它时,我只需要编写实现 IJob 接口的新作业。我将其注册为

        IpcChannel channel = new IpcChannel("CurrentIPC");

        ChannelServices.RegisterChannel(channel);

        RemotingConfiguration.RegisterWellKnownServiceType(
            typeof(SimpleJob), "SimpleJob", WellKnownObjectMode.SingleCall);
        RemotingConfiguration.RegisterWellKnownServiceType(
            typeof(ComplexObject), "ComplexObject", WellKnownObjectMode.SingleCall);

在这种情况下,我将注册两种工作类型。然后在调度作业时,我将传递类的名称,在代表客户端的 Windows 服务端(在 webapp 端执行对象),我只需将传递的类名称与 IJob 绑定,如下所示:

Dictionary<string, IJob> jobs = new Dictionary<string, IJob>();
    void AddJob(string name)
    {
        IJob obj = (IJob)Activator.GetObject(typeof(IJob), string.Format("ipc://CurrentIPC/{0}", name));
        jobs.Add(name, obj);
    }

所以现在我不需要担心对我的应用程序和其他东西的引用,调度程序会在不知道任何事情的情况下完成它的工作,只需要 IJob 接口并在 webapp 端执行任务。

如果我错了或者它太复杂了,还有其他一些更简单的方法可以做到这一点,或者有一些我不知道的陷阱,你能帮我吗?谢谢你。

PS 还有一个想法是有一个单独的调度程序,它将通过执行 Web 应用程序中指定服务的链接直接运行 Web 应用程序方法,例如“http://localhost:3030/Request/12”,仅此而已,但是在我的网络应用程序中,您应该被授权执行此类请求,并且我们再次遇到需要解决的问题,并且在数千个计划任务的情况下,我们将对此类请求的网络服务器产生额外的负载。

4

5 回答 5

2

我认为您走在正确的轨道上,由于应用程序池回收问题,我将使用 Quartz.NET 创建调度程序并将其托管在 Windows 服务中。

它将使用特定 URL:s 为您的 Web 应用程序或单独的 Web 服务实例中的每个任务/服务触发 Web 应用程序中的任务/服务。

使用这种分离,调度程序只需要知道 url 和调度,而不需要直接引用您的应用程序。这也可以在未来的项目中重复使用。

于 2012-07-08T15:23:15.013 回答
1

我想有点晚了,但仍然对其他人有用。

这是一个我花了很多时间处理的项目,它似乎满足了大部分的要求——事实上,我几乎只将它用于问题中描述的回调工作。这也是我们内部使用的,所以我会尽量保持更新。

http://backgroundworker.codeplex.com/

它与 Quartz 非常相似,但更侧重于管理工作及其数据。

于 2012-10-28T07:16:38.743 回答
1

我知道在 webapp 中托管调度不是一个好主意,因为 webserver 可以回收应用程序池等,所以我决定在 Windows 服务中使用它...

为什么复杂?为什么不让它变得简单,并使用外部服务在一段时间内运行 webhook?

我使用了这项服务,我很高兴,虽然它很容易,我可以根据这个简单的过程创建自己的服务:

http://momentapp.com/

简化通话:

private void Run() {
     try {
        var work = RequestNewMessage();  // get work
        ProcessWork(work);  // process work
        // Log work 
     }
     catch(Exception ex) {
        // Log Error
     }
     finally {
        // set job for now plus1 minute
        SetRecuringJob(DateTime.UtcNow.AddMinute(1)); 
     }
}

private void SetRecuringJob(DateTime dt) {
    PostJob("https://momentapp.com/jobs/new?job[at]={0:s}&job[method]=POST&job[uri]=http://yourapp.com/", dt);
}
于 2012-07-03T07:39:10.353 回答
0

我可能缺少一个要求,但由于您似乎能够安装自定义服务,听起来您可以完全控制那台机器。因此,您不妨为您的重复性工作安排一个 Windows 任务,这应该为重复性任务提供一个非常坚实的基础。

然后,您可以安排一个 VB 脚本来及时加载 URL,如下所示:http: //4rapiddev.com/internet/call-or-open-a-web-page-url-by-using-windows-task -调度程序或cronjob/

当然,从批处理文件到 powershell 到自定义可执行文件,任何事情都会发生。

这种方法的好处:

  • 您可以依赖默认操作系统行为来了解操作系统擅长的方面:调度 :)
  • 管理员已经有了一个 UI(尽管不是 Web UI)
  • 你没有依赖,但操作系统

可能的缺点:

编辑:我似乎确实错过了身份验证的要求,但是当您使用 Windows 时,您可以允许在应用程序的某个区域内进行 Windows 身份验证。而且因为您使用的是经过 Windows 身份验证的计划任务,所以您已经涵盖了这一点。我从未在 ASP.NET 应用程序中大量使用 Windows 身份验证,但您甚至可以只使用自定义配置而无需额外编程。

于 2012-07-09T22:37:48.910 回答
0

如果您的问题是您不想从 WindowService 引用整个 Web 应用程序,并且我同意这一点,那么您为什么不简单地创建一个实用程序 dll 来实现能够通过普通 http url 调用您的 Web 应用程序的通用作业并将“动作”实现为 WCF REST 服务?我认为这将清理一些架构并保持组织中的调度程序服务绝缘(和可重用)。

于 2012-07-09T07:51:59.817 回答