Skip to content

Commit ef8c832

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 bd5f9e5 commit ef8c832

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;
@@ -655,6 +656,7 @@ public function getEventFeedAction(
655656
$response->setCallback(function () use ($format, $cid, $contest, $request, $since_id, $types, $strict, $stream, $metadataFactory, $kernel) {
656657
$lastUpdate = 0;
657658
$lastIdSent = max(0, $since_id); // Don't try to look for event_id=0
659+
$lastIdExists = $since_id === -1;
658660
$typeFilter = false;
659661
if ($types) {
660662
$typeFilter = explode(',', $types);
@@ -722,19 +724,31 @@ public function getEventFeedAction(
722724
// Add missing state events that should have happened already.
723725
$this->eventLogService->addMissingStateEvents($contest);
724726

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

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

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

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

0 commit comments

Comments
 (0)