<?php
require 'examples/boot.php';
require_once dirname(__DIR__).'/Support.php';
use Cognesy\Tell\Resource\TellResourceObservers;
use Cognesy\Tell\Resource\TellShellJobApprovals;
use Cognesy\Tell\Resource\TellResourceEvent;
use Cognesy\Tell\Resource\TellResourceHost;
use Cognesy\Tell\Shell\TellShellJobPolicy;
use Cognesy\Tell\Shell\TellShellJobRequest;
$project = TellHarnessExample::project();
$events = new ArrayObject;
$host = TellResourceHost::shellJobs(
project: $project,
policy: new TellShellJobPolicy(
maxConcurrentJobs: 2,
maxLifetimeMs: 5_000,
maxRetainedOutputBytes: 16_384,
),
approval: TellShellJobApprovals::allowAll(),
observer: TellResourceObservers::callback(
static fn (TellResourceEvent $event) => $events->append($event->toArray()),
),
)->boot();
try {
$script = <<<'PHP'
fwrite(STDOUT, "started\n");
usleep(50_000);
fwrite(STDOUT, "finished\n");
fwrite(STDERR, "diagnostic\n");
PHP;
$command = escapeshellarg(PHP_BINARY).' -r '.escapeshellarg($script);
$started = $host->jobs()->start(
TellShellJobRequest::command($command)
->forMilliseconds(2_000)
->retaining(4_096)
->named('example-worker'),
);
// The process remains host-owned after start() returns. Callers retain
// only immutable snapshots and cursored output, never a raw process handle.
$finished = $host->jobs()->wait($started->id, 3_000);
$output = $host->jobs()->read($started->id);
echo $output->text();
echo 'State: '.$finished->state->value."\n";
echo 'Resource events: '.count($events)."\n";
assert($finished->isTerminal());
assert($finished->exitCode === 0);
assert(str_contains($output->text(), 'started'));
assert(str_contains($output->text(), 'diagnostic'));
} finally {
// This also cancels any still-running jobs, in reverse ownership order.
$host->dispose();
TellHarnessExample::remove($project);
}