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