Files
temporalio-test/app/Temporal/WebhookDelivery/WebhookDeliveryWorkflow.php
2026-05-09 01:18:51 +02:00

123 lines
4.3 KiB
PHP

<?php
namespace App\Temporal\WebhookDelivery;
use Carbon\CarbonInterval;
use Temporal\Activity\ActivityOptions;
use Temporal\Common\RetryOptions;
use Temporal\Workflow;
class WebhookDeliveryWorkflow implements WebhookDeliveryWorkflowInterface
{
private array $endpointStatuses = [];
private int $totalDelivered = 0;
private int $totalFailed = 0;
private int $totalDeadLettered = 0;
private int $retryCount = 0;
/** @var WebhookDeliveryActivityInterface */
private $deliveryStub;
/** @var WebhookDeliveryActivityInterface */
private $deadLetterStub;
public function __construct()
{
$this->deliveryStub = Workflow::newActivityStub(
WebhookDeliveryActivityInterface::class,
ActivityOptions::new()
->withStartToCloseTimeout(CarbonInterval::seconds(30))
->withRetryOptions(
RetryOptions::new()
->withMaximumAttempts(3)
->withInitialInterval(CarbonInterval::seconds(1))
->withBackoffCoefficient(3.0)
)
);
$this->deadLetterStub = Workflow::newActivityStub(
WebhookDeliveryActivityInterface::class,
ActivityOptions::new()
->withStartToCloseTimeout(CarbonInterval::seconds(10))
->withRetryOptions(
RetryOptions::new()->withMaximumAttempts(1)
)
);
}
public function deliver(array $payload, array $endpoints, array $simulationConfig = []): \Generator
{
// Initialize endpoint statuses
foreach ($endpoints as $endpoint) {
$this->endpointStatuses[$endpoint] = [
'status' => 'pending',
'attempt' => 0,
'responseTime' => 0,
];
}
// Fan-out: deliver to all endpoints in parallel
$promises = [];
foreach ($endpoints as $endpoint) {
$this->endpointStatuses[$endpoint]['status'] = 'delivering';
$promises[$endpoint] = Workflow::async(function () use ($endpoint, $payload, $simulationConfig) {
try {
$result = yield $this->deliveryStub->deliverToEndpoint($endpoint, $payload, $simulationConfig);
return ['endpoint' => $endpoint, 'success' => true, 'result' => (array) $result];
} catch (\Throwable $e) {
return ['endpoint' => $endpoint, 'success' => false, 'error' => $e->getMessage()];
}
});
}
// Collect results from all parallel activities
foreach ($promises as $endpoint => $promise) {
$outcome = (array) (yield $promise);
if ($outcome['success']) {
$result = $outcome['result'];
$this->endpointStatuses[$endpoint] = [
'status' => 'delivered',
'attempt' => $result['attempt'] ?? 1,
'responseTime' => $result['responseTime'] ?? 0,
];
$this->totalDelivered++;
$attempt = $result['attempt'] ?? 1;
if ($attempt > 1) {
$this->retryCount += ($attempt - 1);
}
} else {
$this->endpointStatuses[$endpoint]['status'] = 'failed';
$this->totalFailed++;
// Dead-letter failed deliveries
yield $this->deadLetterStub->deadLetter($endpoint, $payload, $outcome['error'] ?? 'Unknown error');
$this->endpointStatuses[$endpoint]['status'] = 'dead_lettered';
$this->totalDeadLettered++;
}
}
return [
'status' => 'completed',
'totalDelivered' => $this->totalDelivered,
'totalFailed' => $this->totalFailed,
'totalDeadLettered' => $this->totalDeadLettered,
'retryCount' => $this->retryCount,
'endpoints' => $this->endpointStatuses,
];
}
public function getDeliveryStatus(): array
{
return [
'totalDelivered' => $this->totalDelivered,
'totalFailed' => $this->totalFailed,
'totalDeadLettered' => $this->totalDeadLettered,
'retryCount' => $this->retryCount,
'endpoints' => $this->endpointStatuses,
];
}
}