Skip to content

Commit 0f9a160

Browse files
DOMjudge teameldering
authored andcommitted
Check that last seen event ID exists while emitting the event feed
This will throw an error, for example, when the database gets reloaded while there is a running process serving the event feed to a connected client. We encountered this problem at WF Astana.
1 parent 0d62cb0 commit 0f9a160

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

webapp/src/Controller/API/ContestController.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use Symfony\Component\HttpFoundation\StreamedResponse;
4040
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
4141
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
42+
use Symfony\Component\HttpKernel\Exception\HttpException;
4243
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
4344
use Symfony\Component\HttpKernel\KernelInterface;
4445
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
@@ -654,6 +655,7 @@ public function getEventFeedAction(
654655
$response->setCallback(function () use ($format, $cid, $contest, $request, $since_id, $types, $strict, $stream, $metadataFactory, $kernel) {
655656
$lastUpdate = 0;
656657
$lastIdSent = max(0, $since_id); // Don't try to look for event_id=0
658+
$lastIdExists = $since_id === -1;
657659
$typeFilter = false;
658660
if ($types) {
659661
$typeFilter = explode(',', $types);
@@ -721,19 +723,31 @@ public function getEventFeedAction(
721723
// Add missing state events that should have happened already.
722724
$this->eventLogService->addMissingStateEvents($contest);
723725

724-
// We fetch *all* events after the last seen to check that
726+
// We fetch *all* events from the last seen to check that
725727
// we don't skip events that are committed out of order.
728+
// This includes the last seen event itself, just to check
729+
// that the database is consistent and, for example, has
730+
// not been reloaded while this process is (long) running.
726731
$q = $this->em->createQueryBuilder()
727732
->from(Event::class, 'e')
728733
->select('e')
729-
->andWhere('e.eventid > :lastIdSent')
734+
->andWhere('e.eventid >= :lastIdSent')
730735
->setParameter('lastIdSent', $lastIdSent)
731736
->orderBy('e.eventid', 'ASC')
732737
->getQuery();
733738

734739
/** @var Event[] $events */
735740
$events = $q->getResult();
736741

742+
if ($lastIdExists) {
743+
if (count($events) == 0 || $events[0]->getEventid() !== $lastIdSent) {
744+
throw new HttpException(500, sprintf('Cannot find event %d in database anymore', $lastIdSent));
745+
}
746+
// Remove the previously last sent event. We just fetched
747+
// it to make sure it's there.
748+
unset($events[0]);
749+
}
750+
737751
// Look for any missing sequential events and wait for them to
738752
// be committed if so.
739753
$missingEvents = false;
@@ -860,6 +874,7 @@ public function getEventFeedAction(
860874
flush();
861875
$lastUpdate = Utils::now();
862876
$lastIdSent = $event->getEventid();
877+
$lastIdExists = true;
863878
$numEventsSent++;
864879

865880
if ($missingEvents && $event->getEventid() >= $lastFoundId) {

0 commit comments

Comments
 (0)