我有一个SQL Server表,其中包含我的程序需要“跟进”的订单(调用web服务以查看是否已完成某些操作)。我的应用程序是多线程的,可以在多个服务器上运行实例。目前,每隔一段时间(在一个线程计时器上),该进程就会从“未经证实的”命令列表中随机选择100行(ORDER BY NEWID()
),然后检查它们,标记出任何成功返回的行。
问题在于线程之间以及不同进程之间存在很多重叠,并且它们无法保证很快就会检查新订单。此外,一些订单永远不会被“确认”并且已经死亡,这意味着它们会妨碍需要确认的订单,如果我一遍又一遍地选择它们,会减慢流程。
我更喜欢的是系统地检查所有未完成的订单。我可以想到两个简单的方法:
我还缺少其他任何想法吗?这甚至有意义吗?如果我需要澄清,请告诉我。
结果:
我最终做的是在我的表中添加一个LastCheckedForConfirmation列,其中包含已完成的订单,我添加了一个存储过程,使用GETDATE()更新单个未确认的行并启动订单号,以便我的流程可以检查它。它尽可能多地旋转(假设进程愿意运行的线程数),并使用存储过程为每个线程获取一个新的OrderNumber。
要处理“不要尝试行太多次或太旧时”的问题,我这样做了:如果“自上次尝试以来的时间”> SP将只返回一行。 “创造和最后一次尝试之间的时间”,所以每次再次尝试需要两倍的时间 - 首先等待5秒,然后是10,然后是20,40,80,120,然后再尝试15次(6次)小时),它放弃了该订单,SP将永远不会再返回。
感谢大家的帮助 - 我知道我这样做的方式不太理想,我很欣赏你指出正确的方向。
答案 0 :(得分:7)
我建议阅读并内化Using tables as Queues。
如果您将数据用作队列,必须正确组织数据以进行排队操作。我链接的文章详细介绍了如何执行此操作,您拥有的是Pending Queue的变体。
你必须绝对摆脱的一件事是随机性。如果在查询中有一件事难以重现,那就是随机性。 ORDER BY NEWID()
将扫描每一行,生成一个guid,然后排序,然后返回前100名。在任何情况下,您都不能让每个工作线程每次扫描整个表,随着未处理条目数量的增加,您将终止服务器。
而是使用待处理日期。通过处理日期列(当项目需要重试时)组织(聚集)队列,并使用我在链接文章中显示的技术出列队列。如果要重试,则出列推迟项目而不是删除它,即。 WITH (...) UPDATE SET due_date = dateadd(day, 1, getutcdate()) ...
答案 1 :(得分:2)
显而易见的方法是在订单中添加列LastCheckDt
。在每个线程中,检索已经过去最长时间而不进行检查的订单。在检索订单的过程中,更新LastCheckDt
字段。
我不会一次检索100个订单,在您的线程到达之前,数据库中存在第50个订单更改的风险。获得一个订单,完成后,获取下一个订单。
此外,我最初开发的过程没有多线程。检查未结订单通常足够快,可以顺序完成。
答案 2 :(得分:0)
您可能想要考虑的一个策略是这样的表格;
JobID bigint PK not null,WorkerID int / nvarchar(max)null
其中worker是正在处理它的服务器的id / name,如果没有人接收到该作业,则为null。当服务器选择一个作业时,它会将自己的id / name放入该列,以指示其他人不要接受该作业。
一个问题是,工作的服务器可能崩溃,使得工作永远不会完成。您可以添加一个代表超时的日期列,该值在工作人员将工作提取到现在时设置+您认为合适的时间范围。
编辑:忘记提及,您需要在完成时删除作业,或者有一个状态字段来表示完成。附加字段可以指示作业的参数,以使您的作业表通用:即。不要只为您的订单制定解决方案,而是要建立一个可以处理将来需要的任何工作的工作经理。