如何在一个脚本执行期间多次刷新学说连接?
how to refresh doctrine connection multiple times during one script execution?
我需要非常频繁地执行 Symfony 命令(比如每 5-10 秒),但是我的 运行time 环境将 cron 触发的最短时间限制为 1 分钟。所以,我想出了一个非常糟糕的解决方案,看起来像这样。我已经创建了 AbstractRepetitiveCommand
class,然后对其进行了扩展,提供了 workToExecute
方法的实现。
abstract class AbstractRepetitiveCommand extends Command
{
protected int $overallMinutes = 1;
protected int $timesPerMinute = 60;
protected function execute(InputInterface $input, OutputInterface $output)
{
$startTime = microtime(true);
while (microtime(true) < $startTime + 60 * $this->overallMinutes - 60 / $this->timesPerMinute) {
if (isset($last) && microtime(true) < $last + 60 / $this->timesPerMinute) {
continue;
}
$last = microtime(true);
$this->workToExecute($input, $output);
}
}
protected function workToExecute(InputInterface $input, OutputInterface $output)
{
return;
}
}
class DoChecksCommand extends AbstractRepetitiveCommand
{
protected int $overallMinutes = 5;
protected int $timePerMinute = 4;
protected static $defaultName = 'checks:do';
/**
* @var InvestmentCheckerService
*/
private InvestmentCheckerService $checkerService;
/**
* @var EntityManagerInterface
*/
private EntityManagerInterface $entityManager;
public function __construct(InvestmentCheckerService $checkerService, EntityManagerInterface $entityManager)
{
parent::__construct('DoChecks');
$this->checkerService = $checkerService;
$this->entityManager = $entityManager;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @throws \Exception
*/
protected function workToExecute(InputInterface $input, OutputInterface $output)
{
/** @var ArrayCollection | Pair[] $pairs */
$pairs = $this->entityManager->getRepository(Pair::class)->findAll();
foreach ($pairs as $pair) {
$this->checkerService->processChecks($pair);
$this->entityManager->persist($pair);
$this->entityManager->flush();
}
}
}
这种方法有两个问题:
- 当2个这样的命令同时运行时,它们不会
识别彼此通过 flush 所做的更改。有没有办法
刷新连接,所以每个 运行 数据都是从
数据库?
- 这个解决方案整体来说真的很难看。我大概
overthinking/overcomplicating 它,所以请告知您是否看到任何
更好地实现我想要实现的目标。
现在我尝试在每个循环开始时使用 EntityManager
的 clear()
方法,但它没有改变任何东西。
我考虑过关闭连接,但是我没有看到任何简单的方法可以在关闭后重新连接。
感谢您的帮助。
For now I've tried to use clear() method of EntityManager at the start of every loop but it didn't change anything.
这正是您需要做的。清除 EntityManager 后,Doctrine 将发出数据库查询以获取新数据,因此您在其他 commands/request 中所做的任何更改都将对您可用。唯一不真实的情况是未关闭的交易,但我在您的代码中没有看到明确的交易,所以一切都应该没问题。
我需要非常频繁地执行 Symfony 命令(比如每 5-10 秒),但是我的 运行time 环境将 cron 触发的最短时间限制为 1 分钟。所以,我想出了一个非常糟糕的解决方案,看起来像这样。我已经创建了 AbstractRepetitiveCommand
class,然后对其进行了扩展,提供了 workToExecute
方法的实现。
abstract class AbstractRepetitiveCommand extends Command
{
protected int $overallMinutes = 1;
protected int $timesPerMinute = 60;
protected function execute(InputInterface $input, OutputInterface $output)
{
$startTime = microtime(true);
while (microtime(true) < $startTime + 60 * $this->overallMinutes - 60 / $this->timesPerMinute) {
if (isset($last) && microtime(true) < $last + 60 / $this->timesPerMinute) {
continue;
}
$last = microtime(true);
$this->workToExecute($input, $output);
}
}
protected function workToExecute(InputInterface $input, OutputInterface $output)
{
return;
}
}
class DoChecksCommand extends AbstractRepetitiveCommand
{
protected int $overallMinutes = 5;
protected int $timePerMinute = 4;
protected static $defaultName = 'checks:do';
/**
* @var InvestmentCheckerService
*/
private InvestmentCheckerService $checkerService;
/**
* @var EntityManagerInterface
*/
private EntityManagerInterface $entityManager;
public function __construct(InvestmentCheckerService $checkerService, EntityManagerInterface $entityManager)
{
parent::__construct('DoChecks');
$this->checkerService = $checkerService;
$this->entityManager = $entityManager;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @throws \Exception
*/
protected function workToExecute(InputInterface $input, OutputInterface $output)
{
/** @var ArrayCollection | Pair[] $pairs */
$pairs = $this->entityManager->getRepository(Pair::class)->findAll();
foreach ($pairs as $pair) {
$this->checkerService->processChecks($pair);
$this->entityManager->persist($pair);
$this->entityManager->flush();
}
}
}
这种方法有两个问题:
- 当2个这样的命令同时运行时,它们不会 识别彼此通过 flush 所做的更改。有没有办法 刷新连接,所以每个 运行 数据都是从 数据库?
- 这个解决方案整体来说真的很难看。我大概 overthinking/overcomplicating 它,所以请告知您是否看到任何 更好地实现我想要实现的目标。
现在我尝试在每个循环开始时使用 EntityManager
的 clear()
方法,但它没有改变任何东西。
我考虑过关闭连接,但是我没有看到任何简单的方法可以在关闭后重新连接。
感谢您的帮助。
For now I've tried to use clear() method of EntityManager at the start of every loop but it didn't change anything.
这正是您需要做的。清除 EntityManager 后,Doctrine 将发出数据库查询以获取新数据,因此您在其他 commands/request 中所做的任何更改都将对您可用。唯一不真实的情况是未关闭的交易,但我在您的代码中没有看到明确的交易,所以一切都应该没问题。