1. Go to this page and download the library: Download zuqongtech/laravel-kronos library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
zuqongtech / laravel-kronos example snippets
namespace App\Providers;
use App\Jobs\GenerateMemberStatementsJob;
use App\Jobs\NotifyStakeholdersJob;
use App\Jobs\ValidateContributionsJob;
use App\Models\ScheduledTask;
use Illuminate\Support\ServiceProvider;
use ZuqongTech\Kronos\Facades\Kronos;
class KronosServiceProvider extends ServiceProvider
{
public function boot(): void
{
// ── Rule: when a ScheduledTask is enabled, write it to kronos.yaml ──
Kronos::rule('activate_scheduled_task')
->when(ScheduledTask::class, fn ($task) => $task->is_enabled)
->onEvents(['created', 'updated'])
->produces(fn ($task) => [
'id' => $task->id,
'command' => $task->command,
'cron_expression' => $task->cron_expression,
'timezone' => $task->timezone ?? 'UTC',
'without_overlapping' => true,
'on_one_server' => true,
'enabled' => true,
]);
// ── Workflow: multi-step monthly payroll ───────────────────────────
Kronos::workflow('monthly_payroll')
->trigger()->cron('0 0 1 * *')->timezone('Pacific/Port_Moresby')
->step('validate_contributions')
->run(ValidateContributionsJob::class)
->retries(3, delaySeconds: 120)
->timeout(300)
->step('generate_statements')
->run(GenerateMemberStatementsJob::class)
->after('validate_contributions')
->timeout(600)
->step('notify_stakeholders')
->run(NotifyStakeholdersJob::class)
->after('generate_statements')
->retries(2)
->onFailure(fn () => \Log::critical('Monthly payroll workflow failed'))
->register();
}
}
namespace App\Jobs;
use ZuqongTech\Kronos\Contracts\KronosStep;
use ZuqongTech\Kronos\DAG\WorkflowContext;
class ValidateContributionsJob implements KronosStep
{
public function handle(WorkflowContext $context): array
{
$result = ContributionValidator::run();
// Write to shared context — available to all downstream steps
$context->set('validated_count', $result->count);
$context->set('has_errors', $result->hasErrors());
return ['count' => $result->count];
}
}
class ParseRecordsJob implements KronosStep
{
public function handle(WorkflowContext $context): array
{
// Read data written by the previous step
$filePath = $context->get('validated_file_path');
$records = RecordParser::parse($filePath);
// Write for downstream steps
$context->set('record_count', count($records));
$context->set('parse_errors', $records->errors());
return ['parsed' => count($records)];
}
}
$context->get('key', $default); // Read a value
$context->set('key', $value); // Write and persist immediately
$context->has('key'); // Check existence
$context->forget('key'); // Remove a key
$context->merge(['a' => 1, ...]); // Bulk write
$context->all(); // Get all data
namespace App\Jobs;
use ZuqongTech\Kronos\Contracts\KronosStep;
use ZuqongTech\Kronos\DAG\WorkflowContext;
class SendPayrollNotificationsJob implements KronosStep
{
/**
* Execute this step.
*
* @return array|null Return an array to store as step output, or null.
*/
public function handle(WorkflowContext $context): array|null
{
$count = $context->get('record_count', 0);
Notification::send(
User::role('payroll-admin')->get(),
new PayrollCompletedNotification($count)
);
return ['notified_count' => User::role('payroll-admin')->count()];
}
}
->step('my_step')
->run(MyStepJob::class, ['param' => 'value']) // constructor params
->after('upstream_step') // dependency
->retries(3, delaySeconds: 60) // retry 3x, 60s backoff
->timeout(300) // 5 minute timeout
->parallel() // hint: can run in parallel
->skipUnless('context_key') // skip if context key is falsy
->onSuccess(fn () => Log::info('...'))
->onFailure(fn () => Slack::send('#alerts', '...'))
// app/Providers/Filament/AdminPanelProvider.php
use ZuqongTech\Kronos\Filament\KronosPlugin;
->plugins([
KronosPlugin::make(),
])
use ZuqongTech\Kronos\Events\WorkflowCompleted;
use ZuqongTech\Kronos\Events\WorkflowFailed;
use ZuqongTech\Kronos\Events\WorkflowStepCompleted;
use ZuqongTech\Kronos\Events\WorkflowStepFailed;
// config/kronos.php
return [
// Path to the canonical YAML config file
'config_path' => storage_path('kronos.yaml'),
// Enable multi-node / distributed mode
// Sets onOneServer() on all entries and uses Redis as primary config store
'multi_node' => env('KRONOS_MULTI_NODE', false),
// Redis connection name (from config/database.php)
'redis_connection' => env('KRONOS_REDIS_CONNECTION', 'default'),
// Queue connection and name for Kronos internal jobs
'queue' => [
'connection' => env('KRONOS_QUEUE_CONNECTION', 'redis'),
'name' => env('KRONOS_QUEUE_NAME', 'kronos'),
],
// Inbound webhook trigger endpoint
'webhook' => [
'enabled' => env('KRONOS_WEBHOOK_ENABLED', false),
'secret' => env('KRONOS_WEBHOOK_SECRET'),
'prefix' => env('KRONOS_WEBHOOK_PREFIX', 'kronos'),
],
// Run history retention in days (null = keep forever)
'retention_days' => env('KRONOS_RETENTION_DAYS', 30),
// Filament UI plugin settings
'filament' => [
'enabled' => env('KRONOS_FILAMENT_ENABLED', true),
'panel_id' => env('KRONOS_FILAMENT_PANEL', 'admin'),
'nav_group' => 'Kronos',
'nav_sort' => 90,
],
// Default timezone for all schedules
'timezone' => env('KRONOS_TIMEZONE', 'UTC'),
];
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Event;
use ZuqongTech\Kronos\Events\WorkflowCompleted;
use ZuqongTech\Kronos\Jobs\ExecuteWorkflowStep;
it('triggers the monthly payroll workflow', function () {
Bus::fake();
Event::fake();
$runId = Kronos::trigger('monthly_payroll');
Bus::assertDispatched(ExecuteWorkflowStep::class, fn ($job) =>
$job->stepName === 'validate_contributions'
);
});
it('fires WorkflowCompleted on success', function () {
Event::fake();
// Simulate a completed run
$run = KronosWorkflowRun::factory()->completed()->create();
event(new WorkflowCompleted($run));
Event::assertDispatched(WorkflowCompleted::class);
});
it('writes validated_count to context', function () {
$run = KronosWorkflowRun::factory()->create(['context' => []]);
$context = new WorkflowContext($run);
$job = new ValidateContributionsJob();
$output = $job->handle($context);
expect($output)->toHaveKey('count')
->and($context->get('validated_count'))->toBeInt();
});