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
)。太长,读不下去了我建议你吃芹菜@洛德隆感谢你付出了一些努力,试图找到一个“纯”的解决方案!我仍在努力寻找一种不会超过芹菜所需开销的蔬菜,但恐怕我会同意你的看法。无论如何,如果你想分享你的思路与这个“纯”的解决方案,我会非常感谢你!