Search by

fusonic / sentry-cron

mburtscherdavidrotharjanfransmichaelzangerleDominicLuidold

Automatic Sentry Cron check-ins with Symfony Scheduler

Package info

github.com/fusonic/php-sentry-cron

pkg:composer/fusonic/sentry-cron

Statistics

Installs: 4 814

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

1.0.0 2026-09-02 07:25 UTC

This package is auto-updated.

Last update: 2026-09-02 07:26:26 UTC


README

License Latest Version Total Downloads php 8.2+

About

Automatically register scheduled events from Symfony Scheduler in Sentry Cron. Only cron expressions are supported.

Install

Use composer to install the library from packagist.

composer require fusonic/sentry-cron

Configuration

Fusonic\SentryCron\SentrySchedulerEventSubscriber:
    arguments:
        $enabled: true

If you use async events, also register the messenger subscriber (see that section for why it's needed in addition to the one above):

Fusonic\SentryCron\SentryAsyncCheckInMessengerSubscriber:
    arguments:
        $enabled: true

Usage

Any regular event that is triggered with a cron expression can be used.

Event Configuration

By default, the Sentry defaults are used for monitor configurations. Per event, you can configure an attribute to use your own configuration:

use Fusonic\SentryCron\SentryMonitorConfig;

#[SentryMonitorConfig(checkinMargin: 30, maxRuntime: 30, failureIssueThreshold: 5, recoveryThreshold: 5)]
class SomeEvent {
    // ...
}

Async Events

If you have an unpredictable longer-running scheduled task that batches its work and re-dispatches itself to continue, implement AsyncCheckInScheduleEventInterface.

The scheduled event:

use Fusonic\SentryCron\SentryMonitorConfig;
use Fusonic\SentryCron\AsyncCheckInScheduleEventInterface;
use \Fusonic\SentryCron\AsyncCheckInScheduleEventTrait;

class SomeEvent implements AsyncCheckInScheduleEventInterface {
    use AsyncCheckInScheduleEventTrait;
    
    // ...
}

The handler, threading the check-in ID onto each follow-up batch and marking the last one:

class SomeEventHandler {
    private const BATCH_SIZE = 100;
    
    public function __invoke(SomeEvent $event): void {
        $offset = 0;
        
        // e.g.: some slow database processing
        $entitiesToProcess = // ...
        
        $nextEvent = (new SomeEvent(offset: $offset + self::BATCH_SIZE))->setCheckInId($event->getCheckInId());

        if (count($entitiesToProcess) === 0) {
            $nextEvent->markAsLast();
        }

        $this->eventBus->dispatch($nextEvent);
    }

}

Why this needs a second subscriber. Symfony Scheduler's own PreRunEvent/PostRunEvent/FailureEvent only fire for the message Scheduler itself dispatched — once your handler re-dispatches a follow-up message onto a Messenger transport, Scheduler never sees it again. SentrySchedulerEventSubscriber therefore only starts the check-in for async events (on PreRunEvent); completing or failing it is handled entirely by SentryAsyncCheckInMessengerSubscriber, which listens to Messenger's own WorkerMessageHandledEvent/WorkerMessageFailedEvent instead — these fire for every batch, on every transport hop, and are retry-aware (a failure Messenger will retry is not reported as an error).

Those Worker events are only dispatched for messages actually consumed by a real (queued) transport. If an async event is ever routed to sync://, or to a bus with no matching transport at all, it's handled in-process without ever going through a Worker, so neither subscriber can complete or fail its check-in — it will hang at in_progress until Sentry's maxRuntime times it out and flags it as missed. Make sure every message implementing AsyncCheckInScheduleEventInterface is routed to a transport with a real consumer.