|
39 | 39 | use Symfony\Component\HttpFoundation\StreamedResponse; |
40 | 40 | use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; |
41 | 41 | use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; |
| 42 | +use Symfony\Component\HttpKernel\Exception\HttpException; |
42 | 43 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
43 | 44 | use Symfony\Component\HttpKernel\KernelInterface; |
44 | 45 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
@@ -655,6 +656,7 @@ public function getEventFeedAction( |
655 | 656 | $response->setCallback(function () use ($format, $cid, $contest, $request, $since_id, $types, $strict, $stream, $metadataFactory, $kernel) { |
656 | 657 | $lastUpdate = 0; |
657 | 658 | $lastIdSent = max(0, $since_id); // Don't try to look for event_id=0 |
| 659 | + $lastIdExists = $since_id === -1; |
658 | 660 | $typeFilter = false; |
659 | 661 | if ($types) { |
660 | 662 | $typeFilter = explode(',', $types); |
@@ -722,19 +724,31 @@ public function getEventFeedAction( |
722 | 724 | // Add missing state events that should have happened already. |
723 | 725 | $this->eventLogService->addMissingStateEvents($contest); |
724 | 726 |
|
725 | | - // We fetch *all* events after the last seen to check that |
| 727 | + // We fetch *all* events from the last seen to check that |
726 | 728 | // 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. |
727 | 732 | $q = $this->em->createQueryBuilder() |
728 | 733 | ->from(Event::class, 'e') |
729 | 734 | ->select('e') |
730 | | - ->andWhere('e.eventid > :lastIdSent') |
| 735 | + ->andWhere('e.eventid >= :lastIdSent') |
731 | 736 | ->setParameter('lastIdSent', $lastIdSent) |
732 | 737 | ->orderBy('e.eventid', 'ASC') |
733 | 738 | ->getQuery(); |
734 | 739 |
|
735 | 740 | /** @var Event[] $events */ |
736 | 741 | $events = $q->getResult(); |
737 | 742 |
|
| 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 | + |
738 | 752 | // Look for any missing sequential events and wait for them to |
739 | 753 | // be committed if so. |
740 | 754 | $missingEvents = false; |
@@ -861,6 +875,7 @@ public function getEventFeedAction( |
861 | 875 | flush(); |
862 | 876 | $lastUpdate = Utils::now(); |
863 | 877 | $lastIdSent = $event->getEventid(); |
| 878 | + $lastIdExists = true; |
864 | 879 | $numEventsSent++; |
865 | 880 |
|
866 | 881 | if ($missingEvents && $event->getEventid() >= $lastFoundId) { |
|
0 commit comments