repository = $repository ?? new Repository(); $this->sender = $sender ?? static fn( int $id, string $subject, string $body ): bool => ( new EmailService() )->send_custom_booking( $id, $subject, $body, array( 'template' => 'reminder' ) ); $this->clock = $clock ?? static fn(): int => time(); } /** Sends at most $limit due reminders; returns how many the mail transport accepted. */ public function run( int $limit = 10 ): int { if ( BookingLock::is_held() ) { return 0; } $now = (int) ( $this->clock )(); $this->repository->reconcile( $now ); $sent = 0; for ( $i = 0; $i < max( 1, min( 20, $limit ) ); ++$i ) { $now = (int) ( $this->clock )(); $job = $this->repository->claim( $now ); if ( ! $job ) { break; } $settings = $this->repository->begin_send( $job, $now ); if ( ! $settings ) { continue; } try { if ( ! $this->repository->deliverable( $job, (int) ( $this->clock )() ) ) { $this->repository->finish_unsent( $job, (int) ( $this->clock )() ); continue; } $result = ( $this->sender )( (int) $job['appointment_id'], $settings['subject'], $settings['body'] ); $outcome = $result === true ? 'sent' : 'transport_false'; } catch ( \Throwable $error ) { $outcome = 'transport_exception'; } $this->repository->finish( $job, $outcome, (int) ( $this->clock )() ); if ( $outcome === 'sent' ) { ++$sent; } } return $sent; } }