Python 如果数据库中发生变化,如何停止长进程的执行?
我有一个视图,它向Python 如果数据库中发生变化,如何停止长进程的执行?,python,django,multithreading,rabbitmq,Python,Django,Multithreading,Rabbitmq,我有一个视图,它向RabbitMQ队列发送消息 message = {'origin': 'Bytes CSV', 'data': {'csv_key': str(csv_entry.key), 'csv_fields': csv_fields 'order_by': order_by, 'filters': filters}} ... queue_s
RabbitMQ
队列发送消息
message = {'origin': 'Bytes CSV',
'data': {'csv_key': str(csv_entry.key),
'csv_fields': csv_fields
'order_by': order_by,
'filters': filters}}
...
queue_service.send(message=message, headers={}, exchange_name=EXCHANGE_IN_NAME,
routing_key=MESSAGES_ROUTING_KEY.replace('#', 'bytes_counting.create'))
对于我的消费者,我有一个漫长的过程来生成CSV
def create(self, data):
csv_obj = self._get_object(key=data['csv_key'])
if csv_obj.status == CSVRequestStatus.CANCELED:
self.logger.info(f'CSV {csv_obj.key} was canceled by the user')
return
result = self.generate_result_data(filters=data['filters'], order_by=data['order_by'], csv_obj=csv_obj)
csv_data = self._generate_csv(result=result, csv_fields=data['csv_fields'], csv_obj=csv_obj)
file_key = self._post_csv(csv_data=csv_data, csv_obj=csv_obj)
csv_obj.status = CSVRequestStatus.READY
csv_obj.status_additional = CSVRequestStatusAdditional.SUCCESS
csv_obj.file_key = file_key
csv_obj.ready_at = timezone.now()
csv_obj.save(update_fields=['status', 'status_additional', 'ready_at', 'file_key'])
self.logger.info(f'CSV {csv_obj.name} created')
长过程发生在self.\u generate\u csv
内部,因为self.generate\u result\u data
返回一个queryset
,这是惰性的
如您所见,如果用户在消息开始使用之前通过端点更改
csv\u请求的状态,则不会对该过程进行评估。我的目标是在执行self.\u generate\u csv
时让这种情况发生
到目前为止,我尝试使用线程
,但没有成功
我怎样才能实现我的目标
非常感谢 由于self.\u generate\u csv是最慢的,显然解决方案是使用此函数
为此,您可以将csv文件的创建分为几个部分。创建每个工件后,检查状态并查看是否可以继续创建文件。最后,把所有的碎片粘成一个完整的文件
.你为什么不去芹菜图书馆结账呢?使用with比直接利用rabbitmq队列容易得多
芹菜有一个内置的函数revoke
来终止正在进行的任务:
>>来自芹菜.task.control导入撤销
>>>撤销(任务id,终止=True)
对于您的用例,您可能需要(代码片段):
##芹菜/tasks.py
来自芹菜导入应用程序
@应用程序任务(queue=“我的队列”)
def create_csv(消息):
#…剪断。。。
通过
##main.py
来自芹菜导入uuid,当前_应用程序
def start_任务(任务id,消息):
当前应用程序发送任务(
“创建_csv”,
args=[消息],
任务id=任务id,
)
def kill_任务(任务id):
当前应用控制撤销(任务id,终止=True)
##signals.py
从django.dispatch导入接收方
从。模型导入MyModel
from.main导入kill_任务
#选择合适的信号以监听DB变化
@接收器(models.signals.post_save,发送器=MyModel)
def处理程序(发送方,实例,**kwargs):
kill_任务(instance.task_id)
- 使用
芹菜.uuid
生成任务ID,任务ID可以存储在数据库或缓存中,并使用相同的任务ID控制任务,即请求终止
这确实是一个好主意,但是self.\u generate\u csv
不仅生成csv,它还评估queryset
。我可以为最终加入的每个较小的csv切片queryset
,但是如果我多次点击数据库,数据可能会在这两者之间发生变化。或者我可以一次评估整个queryset
,然后像列表一样对其进行切片。这可能确实有效。我要测试一下。谢谢您可以生成一次queryset,只命中db一次,然后对其进行切片或使用迭代器。例如,PostgreSQL使用服务器端游标从数据库中传输结果,而无需将整个结果集加载到内存中。参考:@TrevorCox哇,我从没听说过迭代器!但我仍然需要在N个切片中点击db N次,因为在每一次点击时,我都必须检查csv\u obj
的状态是否发生了变化……”我的目标是在执行self的过程中让这种情况发生。_generate\u csv。“这是什么意思?@LordElrond我想停止这个函数的执行(即使它已经启动)如果csv\u obj
状态更改为CSVRequestStatus.cancelled
。虽然我同意芹菜可以简化事情,但我担心仅为此功能更改所有内容会是一种过度的操作……请注意芹菜.task
会贬值,而且在v5.x
@MuriloSitonio中根本不起作用最初我同意你的看法,因为仅用芹菜来完成这项任务就太过分了。然而,在试图找到一个“纯”的解决方案后,我得出了这样的结论:自己实现它的维护开销将远远超过芹菜所需要的开销,因为它可能需要数百行代码来实现(大概是使用pika
)。太长,读不下去了我建议你吃芹菜@洛德隆感谢你付出了一些努力,试图找到一个“纯”的解决方案!我仍在努力寻找一种不会超过芹菜所需开销的蔬菜,但恐怕我会同意你的看法。无论如何,如果你想分享你的思路与这个“纯”的解决方案,我会非常感谢你!