3

我有当前的设置:

一个常规的 Symfony2 Web 请求可以创建和持久化Job实体,该实体也创建了一个Gearman作业,假设这发生在process 1. Gearman Job 由一个 Gearman 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 实例运行以在 worker 死亡之前处理 5 个 Job。

我的问题是:在工作人员处理 Doctrine2 的第一项工作中,使用以下代码可以毫无问题地从数据库中检索创建的工作:

$job = $this->doctrine
            ->getRepository('AcmeJobBundle:Job')
            ->findOneById($job->workload()); // workload is the job id

然而,一旦这个工作完成并且 for 循环递增以等待第二个工作,假设这是从另一个 Symfony2 Web 请求到达process 3创建Jobwith ID2,即使实体肯定在数据库中,对 Doctrine2 存储库的调用也会返回 null .

重新启动工人解决了这个问题,所以当它执行它的第一个循环时,它可以拾取Job2。

有谁知道为什么会这样?是否第一次调用getRepositoryfindOneById从 MySQL 进行某种表缓存,不允许它看到随后添加的Job2?

只要数据库保持打开状态,MySQL 是否只显示给定连接的数据库快照?

我也试过entityManager在拨打第二次电话之前重置findOneBy无济于事。

提前感谢您的任何建议,这个真的难倒我。

更新:

我创建了一个单进程测试用例来排除是否是并发导致了问题,并且测试用例按预期执行。似乎唯一一次存储库找不到作业 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.
4

1 回答 1

1

也许一个进程在第二个进程保存之前尝试加载实体。

Doctrine 通过其 id 缓存加载的实体,因此当您收到对同一对象的第二次请求时,它会加载而无需对数据库进行另一次查询。你可以在这里了解更多关于 Doctrine IdentityMap的信息

于 2013-04-27T11:21:39.567 回答