Skip to content
Open
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
6 changes: 3 additions & 3 deletions src/Middleware/AbstractMiddlewareStack.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,16 @@ protected function runMiddleware(MiddlewareRegistryInterface $middlewareList, Cl

$this->executedMiddleware->attach(object: $middleware);
});
} catch (Throwable $throwable) {
} catch (Throwable) {
$middlewareList->next();
} finally {
foreach ($requiredMiddlewareList as $singleRequiredMiddlewareList) {
if ($this->executedMiddleware->contains(object: $singleRequiredMiddlewareList)) {
continue;
}

$func($singleRequiredMiddlewareList);
}

throw $throwable;
}
}

Expand Down
9 changes: 9 additions & 0 deletions src/Middleware/MiddlewareRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use function is_array;
use function iterator_to_array;
use function uasort;
use function next;

use const ARRAY_FILTER_USE_BOTH;

Expand Down Expand Up @@ -73,6 +74,14 @@ public function toArray(): array
return $this->middlewareList;
}

/**
* {@inheritdoc}
*/
public function next(): void
{
next(array: $this->middlewareList);
}

/**
* {@inheritdoc}
*/
Expand Down
5 changes: 5 additions & 0 deletions src/Middleware/MiddlewareRegistryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public function walk(Closure $func): MiddlewareRegistryInterface;
*/
public function uasort(Closure $func): MiddlewareRegistryInterface;

/**
* Change the internal cursor of the middleware list, mainly used by {@see AbstractMiddlewareStack::runMiddleware()} to iterate over the list when an exception is thrown.
*/
public function next(): void;

/**
* @return array<int, PostExecutionMiddlewareInterface|PreExecutionMiddlewareInterface|PreSchedulingMiddlewareInterface|PostSchedulingMiddlewareInterface|RequiredMiddlewareInterface|OrderedMiddlewareInterface>
*/
Expand Down
7 changes: 5 additions & 2 deletions src/Middleware/SchedulerMiddlewareStack.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ public function runPostSchedulingMiddleware(TaskInterface $task, SchedulerInterf
*/
public function getMiddlewareList(): array
{
$preSchedulingMiddlewareList = $this->getPreSchedulingMiddleware();
$postSchedulingMiddlewareList = $this->getPostSchedulingMiddleware();

return array_unique(array: [
...$this->getPreSchedulingMiddleware()->toArray(),
...$this->getPostSchedulingMiddleware()->toArray(),
...$preSchedulingMiddlewareList->toArray(),
...$postSchedulingMiddlewareList->toArray(),
], flags: SORT_REGULAR);
}
}
3 changes: 1 addition & 2 deletions src/Worker/Worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,10 @@ protected function handleTask(TaskInterface $task, TaskListInterface $taskList):
$this->taskExecutionTracker->endTracking(task: $task);
$task->setExecutionEndTime(dateTimeImmutable: new DateTimeImmutable());
$task->setLastExecution(dateTimeImmutable: new DateTimeImmutable());

$this->defineTaskExecutionState(task: $task, output: $output);

$this->middlewareStack->runPostExecutionMiddleware(task: $task, worker: $this);
$this->eventDispatcher->dispatch(new TaskExecutedEvent(task: $task, output: $output));

$this->configuration->setLastExecutedTask(lastExecutedTask: $task);

$executedTasksCount = $this->configuration->getExecutedTasksCount();
Expand All @@ -311,6 +309,7 @@ protected function handleTask(TaskInterface $task, TaskListInterface $taskList):
} finally {
$this->configuration->setCurrentlyExecutedTask(task: null);
$this->configuration->run(isRunning: false);

$this->eventDispatcher->dispatch(event: new WorkerRunningEvent(worker: $this, isIdle: true));
}
}
Expand Down
7 changes: 4 additions & 3 deletions tests/Middleware/WorkerMiddlewareStackTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use SchedulerBundle\Middleware\PostExecutionMiddlewareInterface;
use SchedulerBundle\Middleware\PreExecutionMiddlewareInterface;
use SchedulerBundle\Middleware\WorkerMiddlewareStack;
use SchedulerBundle\Task\NullTask;
use SchedulerBundle\Task\TaskInterface;
use SchedulerBundle\Worker\WorkerInterface;
use Throwable;
Expand All @@ -23,7 +24,7 @@ final class WorkerMiddlewareStackTest extends TestCase
*/
public function testStackCanRunEmptyPreMiddlewareList(): void
{
$task = $this->createMock(TaskInterface::class);
$task = new NullTask(name: 'foo');

$middleware = $this->createMock(PostExecutionMiddlewareInterface::class);
$middleware->expects(self::never())->method('postExecute')->with($task);
Expand All @@ -40,7 +41,7 @@ public function testStackCanRunEmptyPreMiddlewareList(): void
*/
public function testStackCanRunPreMiddlewareList(): void
{
$task = $this->createMock(TaskInterface::class);
$task = new NullTask(name: 'foo');

$middleware = $this->createMock(PreExecutionMiddlewareInterface::class);
$middleware->expects(self::once())->method('preExecute')->with($task);
Expand All @@ -62,7 +63,7 @@ public function testStackCanRunPreMiddlewareList(): void
public function testStackCanRunEmptyPostMiddlewareList(): void
{
$worker = $this->createMock(WorkerInterface::class);
$task = $this->createMock(TaskInterface::class);
$task = new NullTask(name: 'foo');

$middleware = $this->createMock(PreExecutionMiddlewareInterface::class);
$middleware->expects(self::never())->method('preExecute')->with($task);
Expand Down
8 changes: 4 additions & 4 deletions tests/SchedulerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,10 @@ public function testSchedulerCannotScheduleTasksWithErroredBeforeCallback(): voi
new TaskCallbackMiddleware(),
])), new EventDispatcher());

self::expectException(RuntimeException::class);
self::expectExceptionMessage('The task cannot be scheduled');
self::expectExceptionCode(0);
$scheduler->schedule(new NullTask('foo', [
self::expectException(exception: RuntimeException::class);
self::expectExceptionMessage(message: 'The task cannot be scheduled');
self::expectExceptionCode(code: 0);
$scheduler->schedule(task: new NullTask(name: 'foo', options: [
'before_scheduling' => static fn (): bool => false,
]));
}
Expand Down
10 changes: 5 additions & 5 deletions tests/Worker/ExecutionPolicy/ExecutionPolicyRegistryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ final class ExecutionPolicyRegistryTest extends TestCase
{
public function testRegistryCanCount(): void
{
$registry = new ExecutionPolicyRegistry([]);
$registry = new ExecutionPolicyRegistry(policies: []);

self::assertCount(0, $registry);
}

public function testRegistryCannotReturnInvalidPolicy(): void
{
$registry = new ExecutionPolicyRegistry([
$registry = new ExecutionPolicyRegistry(policies: [
new DefaultPolicy(),
]);
self::assertCount(1, $registry);
Expand All @@ -36,7 +36,7 @@ public function testRegistryCannotReturnInvalidPolicy(): void

public function testRegistryCannotReturnMultiplePolicies(): void
{
$registry = new ExecutionPolicyRegistry([
$registry = new ExecutionPolicyRegistry(policies: [
new DefaultPolicy(),
new DefaultPolicy(),
]);
Expand All @@ -50,12 +50,12 @@ public function testRegistryCannotReturnMultiplePolicies(): void

public function testRegistryCanReturnPolicy(): void
{
$registry = new ExecutionPolicyRegistry([
$registry = new ExecutionPolicyRegistry(policies: [
new DefaultPolicy(),
]);
self::assertCount(1, $registry);

$policy = $registry->find('default');
$policy = $registry->find(policy: 'default');
self::assertInstanceOf(DefaultPolicy::class, $policy);
}
}
58 changes: 24 additions & 34 deletions tests/Worker/WorkerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,34 +77,30 @@ final class WorkerTest extends TestCase
*/
public function testTaskCannotBeExecutedWithoutRunner(): void
{
$watcher = $this->createMock(TaskExecutionTrackerInterface::class);

$worker = new Worker(
new Scheduler('UTC', new InMemoryTransport(new InMemoryConfiguration(), new SchedulePolicyOrchestrator([
scheduler: new Scheduler(timezone: 'UTC', transport: new InMemoryTransport(new InMemoryConfiguration(), schedulePolicyOrchestrator: new SchedulePolicyOrchestrator(policies: [
new FirstInFirstOutPolicy(),
])), new SchedulerMiddlewareStack([]), new EventDispatcher()),
new RunnerRegistry([]),
new ExecutionPolicyRegistry([]),
$watcher,
new WorkerMiddlewareStack(),
new EventDispatcher(),
new LockFactory(new InMemoryStore()),
new NullLogger()
])), middlewareStack: new SchedulerMiddlewareStack([]), eventDispatcher: new EventDispatcher()),
runnerRegistry: new RunnerRegistry(runners: []),
executionPolicyRegistry: new ExecutionPolicyRegistry(policies: []),
taskExecutionTracker: new TaskExecutionTracker(watch: new Stopwatch()),
middlewareStack: new WorkerMiddlewareStack(),
eventDispatcher: new EventDispatcher(),
lockFactory: new LockFactory(store: new InMemoryStore()),
logger: new NullLogger()
);

self::expectException(UndefinedRunnerException::class);
self::expectExceptionMessage('No runner found');
self::expectExceptionCode(0);
$worker->execute(WorkerConfiguration::create());
self::expectException(exception: UndefinedRunnerException::class);
self::expectExceptionMessage(message: 'No runner found');
self::expectExceptionCode(code: 0);
$worker->execute(configuration: WorkerConfiguration::create());
}

/**
* @throws Throwable {@see WorkerInterface::execute()}
*/
public function testWorkerCanBeConfigured(): void
{
$watcher = $this->createMock(TaskExecutionTrackerInterface::class);

$lockFactory = new LockFactory(new InMemoryStore());

$worker = new Worker(new Scheduler('UTC', new InMemoryTransport(new InMemoryConfiguration(), new SchedulePolicyOrchestrator([
Expand All @@ -113,7 +109,7 @@ public function testWorkerCanBeConfigured(): void
new NullTaskRunner(),
]), new ExecutionPolicyRegistry([
new DefaultPolicy(),
]), $watcher, new WorkerMiddlewareStack([
]), new TaskExecutionTracker(new Stopwatch()), new WorkerMiddlewareStack([
new TaskLockBagMiddleware($lockFactory),
]), new EventDispatcher(), $lockFactory, new NullLogger());

Expand Down Expand Up @@ -183,9 +179,6 @@ public function testWorkerCanBeForked(): void
*/
public function testTaskCannotBeExecutedWithoutSupportingRunner(): void
{
$watcher = $this->createMock(TaskExecutionTrackerInterface::class);
$logger = $this->createMock(LoggerInterface::class);

$transport = new InMemoryTransport(new InMemoryConfiguration(), new SchedulePolicyOrchestrator([
new FirstInFirstOutPolicy(),
]));
Expand All @@ -203,10 +196,10 @@ public function testTaskCannotBeExecutedWithoutSupportingRunner(): void
new ShellTaskRunner(),
]), new ExecutionPolicyRegistry([
new DefaultPolicy(),
]), $watcher, new WorkerMiddlewareStack([
]), new TaskExecutionTracker(new Stopwatch()), new WorkerMiddlewareStack([
new TaskUpdateMiddleware($transport),
new TaskLockBagMiddleware($lockFactory),
]), $eventDispatcher, $lockFactory, $logger);
]), $eventDispatcher, $lockFactory, new NullLogger());
$worker->execute(WorkerConfiguration::create());

self::assertNull($worker->getLastExecutedTask());
Expand All @@ -218,7 +211,7 @@ public function testTaskCannotBeExecutedWithoutSupportingRunner(): void
$task = $failedTask->getTask();
self::assertSame('foo', $task->getName());
self::assertNull($task->getExecutionState());
self::assertNull($task->getLastExecution());
self::assertInstanceOf(DateTimeImmutable::class, $task->getLastExecution());
}

/**
Expand Down Expand Up @@ -507,10 +500,6 @@ public function testTaskCanBeExecutedWithErroredAfterExecutionCallback(): void
$logger = $this->createMock(LoggerInterface::class);
$logger->expects(self::never())->method('info');

$tracker = $this->createMock(TaskExecutionTrackerInterface::class);
$tracker->expects(self::exactly(2))->method('startTracking')->withConsecutive([$task], [$validTask]);
$tracker->expects(self::exactly(2))->method('endTracking')->withConsecutive([$task], [$validTask]);

$transport = new InMemoryTransport(new InMemoryConfiguration(), new SchedulePolicyOrchestrator([
new FirstInFirstOutPolicy(),
]));
Expand All @@ -528,15 +517,16 @@ public function testTaskCanBeExecutedWithErroredAfterExecutionCallback(): void
new NullTaskRunner(),
]), new ExecutionPolicyRegistry([
new DefaultPolicy(),
]), $tracker, new WorkerMiddlewareStack([
]), new TaskExecutionTracker(new Stopwatch()), new WorkerMiddlewareStack([
new SingleRunTaskMiddleware($transport),
new TaskCallbackMiddleware(),
new TaskLockBagMiddleware($lockFactory),
]), $eventDispatcher, $lockFactory, $logger);
$worker->execute(WorkerConfiguration::create());

self::assertCount(1, $worker->getFailedTasks());
self::assertInstanceOf(FailedTask::class, $worker->getFailedTasks()->get('foo.failed'));
$failedTasks = $worker->getFailedTasks();
self::assertCount(1, $failedTasks);
self::assertInstanceOf(FailedTask::class, $failedTasks->get('foo.failed'));
self::assertNotNull($worker->getLastExecutedTask());
self::assertSame($validTask, $worker->getLastExecutedTask());
}
Expand Down Expand Up @@ -1300,8 +1290,8 @@ public function testWorkerCanExecuteChainedTasks(): void
]));

$scheduler = new Scheduler('UTC', $transport, new SchedulerMiddlewareStack(), new EventDispatcher());
$scheduler->schedule($chainedTask);
$scheduler->schedule($shellTask);
$scheduler->schedule(task: $chainedTask);
$scheduler->schedule(task: $shellTask);

$eventDispatcher = new EventDispatcher();
$lockFactory = new LockFactory(new InMemoryStore());
Expand Down Expand Up @@ -1377,7 +1367,7 @@ public function testWorkerCanRetrieveTasksLazily(): void
]), $eventDispatcher, $lockFactory, $logger);

$configuration = WorkerConfiguration::create();
$configuration->mustRetrieveTasksLazily(true);
$configuration->mustRetrieveTasksLazily(mustRetrieveTasksLazily: true);

$worker->execute($configuration);

Expand Down