|
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