我有当前设置:
一个常规的Symfony2 web请求可以创建并持久化Job
实体,该实体还创建了一个Gearman作业,比如说这发生在process 1
中。Gearman作业由Gearman Worker执行,该Worker被传递给Job
实体的ID
。
我还使用Symfony创建了一个Gearman Worker,它作为一个PHP CLI进程运行,让我们调用这个process 2
。
对于那些不熟悉Gearman的人来说,worker代码的操作方式如下:
for loop 5 times
get job from gearman (blocking method call)
get job entity from database
do stuff
从本质上讲,这段代码让一个Symfony2实例在工人死亡之前运行,以处理5个作业。
我的问题是:在工作人员处理的第一个作业上,Doctrine2能够使用以下代码从数据库中检索创建的作业而不会出现问题:
$job = $this->doctrine
->getRepository('AcmeJobBundle:Job')
->findOneById($job->workload()); // workload is the job id
然而,一旦此作业完成,for循环增加以等待第二个作业,比如说,这是从process 3
上的另一个Symfony2 web请求到达的,该请求使用ID
2创建Job
,则对Doctrine2存储库的调用返回null,即使实体肯定在数据库中。
重新启动worker解决了这个问题,所以当它执行第一个循环时,它可以选择Job
2。
有人知道为什么会发生这种事吗?getRepository
或findOneById
的第一次调用是否从MySQL进行了某种表缓存,从而不允许它看到随后添加的Job
2?
MySQL是否只显示给定连接的数据库快照,只要它处于打开状态?
在对findOneBy
进行第二次调用之前,我也尝试过重置entityManager
,但没有成功。
谢谢你提前给我的任何建议,这真的让我很困惑。
更新:
我创建了一个单独的流程测试用例来排除是否是并发导致了问题,并且测试用例按预期执行。存储库似乎唯一一次找不到作业2是在另一个进程中将其添加到数据库中时。
// Job 1 already exists
$job = $this->doctrine
->getRepository('AcmeJobBundle:Job')
->findOneById(1);
$job->getId(); // this is fine.
$em->persist(new Job()); // creates job 2
$em->flush();
$job = $this->doctrine
->getRepository('AcmeJobBundle:Job')
->findOneById(2);
$job->getId(); // this is fine too, no exception.
也许一个进程试图在实体被第二个进程保存之前加载它。
Doctrine根据实体的id缓存加载的实体,这样当您收到对同一对象的第二个请求时,它就加载了,而无需对数据库进行另一次查询。你可以在这里阅读更多关于条令识别图