Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `config/schedule.php` (publishable with the `pollora-schedule` tag) chooses the scheduling driver, `wp-cron` (the default) or `action-scheduler`, by `POLLORA_SCHEDULE_DRIVER`, and lists the hooks that stay on WP-Cron whatever the driver. The `cron` option now indexes every driver's events, so `wp_next_scheduled()`, Site Health and WP Crontrol see the ones Action Scheduler keeps, and WP-Cron never runs them. Changing the driver moves nothing by itself
- `pollora:schedule:list` shows the scheduled events with their type, frequency and driver (`--type`, `--driver`, `--site`, `--network`, `--json`), read from the `cron` option with no query to a driver; an event on WP-Cron on purpose reads `(protected)` or `(fallback)`, one a former driver keeps reads `(to migrate)`. `pollora:schedule:migrate` moves the pending events from one driver to another (`--from`, `--to`, `--dry-run`), in both directions and safe to run again
- `pollora:doctor`, Site Health and an administration notice report a driver that does not exist or is not available (events stay on WP-Cron), and the events a former driver still keeps, with the command that moves them
- The `laravel` scheduling driver (`POLLORA_SCHEDULE_DRIVER=laravel`): every event is a job delayed until it is due, in the application's queue (`database`, Redis or Horizon, SQS), and a worker runs it. There is no table of Pollora's own and no `schedule:run`: the `cron` option is the record of what is scheduled, and cancelling an event takes its entry out of it. A job runs only if the entry still exists with its identifier and time, so a cancelled, moved or duplicated job stops; a recurring event queues its next occurrence once it ran or failed for good, never in the past. `config/schedule.php` gains `laravel.connection`, `queue`, `max_delay` (a job due later than the connection allows, 900 seconds on SQS, wakes and waits again) and `late_after`. On a multisite network the queue is shared, with one worker, and each job runs in the site that scheduled it
- Lost jobs (a flushed Redis, a purged queue) are found again: at most every five minutes, as a request ends and under a lock, and with `php artisan pollora:schedule:recover` (`--network`, `--dry-run`), an event more than `late_after` seconds (600) past its time is queued again with the same identifier, so it never runs twice. `pollora:doctor` and Site Health report late events (no worker), a queue connection that is `sync` or `null`, and a scheduled event that failed for good in the last week

### Changed
- `DiscoveryEngine`, `DiscoveryCacheManager`, `InstancePool` and `ReflectionCache` take their dependencies instead of reaching for `app()` and `config()`; reading `structure-discoverer.cache` moved to `LaravelDiscoveryCacheManagerFactory`. `DiscoveryRegistrar::registerFromContainer()` is now `registerInto()`. These are infrastructure classes, outside the public contracts (`Pollora\Discovery\Domain\*`), which do not change
Expand All @@ -35,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Pollora\Attributes\PostType\PostTypeAttribute` and `Pollora\Attributes\Taxonomy\TaxonomyAttribute`, removed in 15.0: no built-in attribute extends them any more; implement `ConfiguresArguments`

### Removed
- **The Laravel scheduling bridge, with no replacement under the same name**: `wordpress.use_laravel_scheduler`, `Pollora\Schedule\Scheduler`, `SchedulerInterface`, `Events\*` (`AbstractEvent`, `SingleEvent`, `RecurringEvent`), `Jobs\JobDispatcher`, `RegisterSchedulerFiltersUseCase`, the `pre_schedule_event`, `pre_option_cron` and related filters it installed, and the `wp_events` table. Setting the option no longer does anything. To keep WP-Cron events on Laravel's queue, set `POLLORA_SCHEDULE_DRIVER=laravel` and run a worker (`php artisan queue:work`) in place of `schedule:run`; events that sat in `wp_events` are not moved (let `#[Schedule]` and your own code schedule them again, then drop the table: `DROP TABLE <prefix>wp_events`, with the prefix of your database connection). `pollora:doctor` no longer reads the option
- `handle()` on `#[Action]`, `#[Filter]`, `#[WpRestRoute]` and `#[WpRestRoute\Method]`, and `Hook` no longer implements `HandlesAttributes`: `HookDiscovery` and `WpRestDiscovery` register hooks and routes themselves. Only the bug below reached `Action::handle()`, and `WpRestRoute::handle()` wrote to a read-only wrapper

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"pollora/entity": "^1.2",
"pollora/hook": "^2.0",
"pollora/option": "^1.1",
"pollora/schedule": "^0.1.1 || ^1.0",
"pollora/schedule": "^0.1.3 || ^1.0",
"pollora/wp-cli": "^0.1 || ^1.0",
"pollora/wp-rest": "^0.1 || ^1.0",
"watson/rememberable": "^7.1",
Expand Down
34 changes: 33 additions & 1 deletion config/schedule.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,44 @@
| are until php artisan pollora:schedule:migrate moves them, and
| pollora:doctor reminds you.
|
| Supported: "wp-cron", "action-scheduler"
| "laravel" makes each event a job delayed until it is due, in the
| application's queue: it needs a connection that accepts delays (not
| "sync" or "null") and a worker, php artisan queue:work. Nothing else
| runs the events, so without a worker none of them fires.
|
| Supported: "wp-cron", "action-scheduler", "laravel"
|
*/

'driver' => env('POLLORA_SCHEDULE_DRIVER', 'wp-cron'),

/*
|--------------------------------------------------------------------------
| The "laravel" driver
|--------------------------------------------------------------------------
|
| connection: the queue connection of the jobs; null is the application's
| default. On a multisite network every site uses the same one, with a
| single worker.
|
| queue: the queue they wait in; null is the connection's default.
|
| max_delay: the longest delay, in seconds, the connection accepts. A job
| due later waits again when it wakes. null: 900 for SQS, none otherwise.
|
| late_after: an event this many seconds past its time is queued again
| (same identifier, so it never runs twice) when its job was lost.
| Checked every five minutes, or with php artisan pollora:schedule:recover.
|
*/

'laravel' => [
'connection' => env('POLLORA_SCHEDULE_QUEUE_CONNECTION'),
'queue' => env('POLLORA_SCHEDULE_QUEUE'),
'max_delay' => env('POLLORA_SCHEDULE_MAX_DELAY'),
'late_after' => (int) env('POLLORA_SCHEDULE_LATE_AFTER', 600),
],

/*
|--------------------------------------------------------------------------
| Hooks that stay on WP-Cron
Expand Down
4 changes: 0 additions & 4 deletions src/Hook/Infrastructure/Checks/AsyncActionsCheck.php
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,6 @@ private function connectionProblems(): array
*/
private function cronFix(): string
{
if ($this->config->get('wordpress.use_laravel_scheduler')) {
return 'WP-Cron events are Laravel jobs here (wordpress.use_laravel_scheduler): run a queue worker, php artisan queue:work';
}

return $this->inspector->cronRunsOnPageLoad()
? 'The site gets too few visits to run WP-Cron: add a system cron that requests wp-cron.php every minute'
: 'DISABLE_WP_CRON is set (Pollora sets it): add a system cron, e.g. * * * * * curl -s https://example.com/cms/wp-cron.php, or wp cron event run --due-now';
Expand Down
3 changes: 0 additions & 3 deletions src/Providers/PolloraServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

namespace Pollora\Providers;

use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Support\ServiceProvider;
use Log1x\SageDirectives\SageDirectivesServiceProvider;
use Pollora\Ability\Infrastructure\Providers\AbilityServiceProvider;
Expand Down Expand Up @@ -36,7 +35,6 @@
use Pollora\PostType\Infrastructure\Providers\PostTypeServiceProvider;
use Pollora\Role\Infrastructure\Providers\RoleServiceProvider;
use Pollora\Route\Infrastructure\Providers\RouteServiceProvider;
use Pollora\Schedule\Jobs\JobDispatcher;
use Pollora\Schedule\SchedulerServiceProvider;
use Pollora\Taxonomy\Infrastructure\Providers\TaxonomyServiceProvider;
use Pollora\Theme\Infrastructure\Providers\ThemeServiceProvider;
Expand Down Expand Up @@ -125,7 +123,6 @@ public function register(): void
$this->app->register(RouteServiceProvider::class);

$this->app->register(SchedulerServiceProvider::class);
$this->app->singleton(JobDispatcher::class, fn ($app): JobDispatcher => new JobDispatcher($app->make(Dispatcher::class)));

// Authentication service provider
$this->app->register(AuthServiceProvider::class);
Expand Down
19 changes: 19 additions & 0 deletions src/Schedule/Application/Services/ScheduleStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Illuminate\Contracts\Config\Repository;
use Pollora\Schedule\Event;
use Pollora\Schedule\Infrastructure\Drivers\LaravelQueueDriver;
use Pollora\Schedule\Schedule;
use Pollora\Schedule\Support\CronIndex;

Expand Down Expand Up @@ -74,6 +75,24 @@ public function toMigrate(): array
return $counts;
}

/**
* Seconds after which an event of the "laravel" driver counts as late.
*/
public function lateAfter(): int
{
return max(60, (int) $this->config->get('schedule.laravel.late_after', 600));
}

/**
* Events of the "laravel" driver that are late: a job lost, or no worker.
*/
public function late(): int
{
$limit = time() - $this->lateAfter();

return count(array_filter(Schedule::engine()->index(), static fn (Event $event): bool => $event->driver === LaravelQueueDriver::NAME && $event->timestamp < $limit));
}

/**
* The driver of an event, with what sets it apart from the site's: "wp-cron (protected)", "wp-cron (to migrate)".
*/
Expand Down

This file was deleted.

55 changes: 0 additions & 55 deletions src/Schedule/Contracts/EventInterface.php

This file was deleted.

22 changes: 0 additions & 22 deletions src/Schedule/Contracts/JobDispatcherInterface.php

This file was deleted.

103 changes: 0 additions & 103 deletions src/Schedule/Contracts/SchedulerInterface.php

This file was deleted.

Loading
Loading