在Web应用程序(Pyramid)中,我在POST
上创建了某些对象,这些对象需要完成一些工作(主要是从Web上获取内容)。在SQLAlchemy的帮助下,这些对象被持久化到PostgreSQL数据库。由于这些任务可能需要一段时间,因此不会在请求处理程序内部完成,而是卸载到不同主机上的守护程序进程。创建对象后,我将其 ID
(客户端生成 UUID
)并通过ZeroMQ将其发送到守护程序进程。守护进程接收ID
,从数据库中获取对象,它是否正常工作并将结果写入数据库。
问题:
守护程序可以在创建事务提交之前收到ID
。由于我们使用pyramid_tm
,所以当请求处理程序返回时没有错误地提交所有数据库事务,我宁愿这样做。在我的开发系统中,一切都在同一个盒子上运行,因此ZeroMQ闪电般快速。在生产系统上,这很可能不是问题,因为Web应用程序和守护程序在不同的主机上运行,但我不想指望这一点。
这个问题最近才出现,因为我们之前使用的MongoDB的write_convern
为2.只有两个数据库服务器,实体上的write
始终阻止了Web请求,直到实体被持久化为止(这显然不是最好的主意。)
我看到了多种可能的解决方案,但大多数解决方案并不让我满意:
after_created
事件触发它,这非常好,因为它完全解耦了这个过程,从而消除了“忘记”告诉守护进程工作的风险。还认为我仍然需要在守护进程端有READ UNCOMMITTED
隔离级别,这是正确的吗?答案 0 :(得分:0)
这接近你的第二个解决方案:
创建一个缓冲区,从那里删除zeromq消息中的id,让工作者定期轮询这个id-pool。如果它无法从数据库中检索id的对象,请让id位于池中直到下一次轮询,否则从池中删除id。
以某种方式处理系统的异步行为。当id在数据库中持久存在之前不断到达时,无论是否汇集id(并重新轮询相同的id)都会降低吞吐量,因为瓶颈更早。
一个好处是,你可以在此前面运行多个前端。
答案 1 :(得分:0)
我只会使用PostgreSQL的LISTEN
and NOTIFY
功能。 worker可以连接到SQL服务器(它已经必须这样做),并发出相应的LISTEN
。然后,PostgreSQL会在相关交易完成时通知它。触发在SQL服务器中生成通知甚至可能会在有效负载中发送整行,因此工作人员甚至不需要请求任何内容:
CREATE OR REPLACE FUNCTION magic_notifier() RETURNS trigger AS $$
BEGIN
PERFORM pg_notify('stuffdone', row_to_json(new)::text);
RETURN new;
END;
$$ LANGUAGE plpgsql;
有了它,只要它知道有工作要做,就会有必要的信息,所以它可以在没有另一次往返的情况下开始工作。