138 lines
4.4 KiB
PHP
138 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Support\OpsUx;
|
|
|
|
use App\Models\OperationRun;
|
|
use App\Models\Tenant;
|
|
use App\Support\OperationRunOutcome;
|
|
use App\Support\OperationRunStatus;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Collection;
|
|
|
|
final class ActiveRuns
|
|
{
|
|
private const int TERMINAL_SUCCESS_GRACE_SECONDS = 30;
|
|
|
|
public static function queryForTenantId(?int $tenantId): Builder
|
|
{
|
|
return OperationRun::query()
|
|
->where('tenant_id', $tenantId)
|
|
->active()
|
|
->orderByDesc('created_at');
|
|
}
|
|
|
|
public static function shellVisibleQueryForTenantId(?int $tenantId): Builder
|
|
{
|
|
return OperationRun::query()
|
|
->where('tenant_id', $tenantId)
|
|
->where(function (Builder $query): void {
|
|
$query
|
|
->where(function (Builder $activeQuery): void {
|
|
$activeQuery->active();
|
|
})
|
|
->orWhere(function (Builder $successQuery): void {
|
|
$successQuery
|
|
->where('status', OperationRunStatus::Completed->value)
|
|
->where('outcome', OperationRunOutcome::Succeeded->value)
|
|
->whereNotNull('completed_at')
|
|
->where('completed_at', '>=', now()->subSeconds(self::TERMINAL_SUCCESS_GRACE_SECONDS));
|
|
})
|
|
->orWhere(function (Builder $followUpQuery): void {
|
|
$followUpQuery->terminalFollowUp();
|
|
});
|
|
})
|
|
->orderByRaw(
|
|
'case when status in (?, ?) then 0 when status = ? and outcome in (?, ?, ?) then 1 when status = ? and outcome = ? then 2 else 3 end',
|
|
[
|
|
OperationRunStatus::Queued->value,
|
|
OperationRunStatus::Running->value,
|
|
OperationRunStatus::Completed->value,
|
|
OperationRunOutcome::Blocked->value,
|
|
OperationRunOutcome::PartiallySucceeded->value,
|
|
OperationRunOutcome::Failed->value,
|
|
OperationRunStatus::Completed->value,
|
|
OperationRunOutcome::Succeeded->value,
|
|
],
|
|
)
|
|
->orderByRaw('coalesce(completed_at, started_at, created_at) desc')
|
|
->orderByDesc('id');
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, OperationRun>
|
|
*/
|
|
public static function visibleForTenantId(?int $tenantId, int $limit = 3): Collection
|
|
{
|
|
if (! is_int($tenantId) || $tenantId <= 0) {
|
|
return collect();
|
|
}
|
|
|
|
return self::queryForTenantId($tenantId)
|
|
->limit(max(1, $limit))
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, OperationRun>
|
|
*/
|
|
public static function shellVisibleForTenantId(?int $tenantId, int $limit = 3): Collection
|
|
{
|
|
if (! is_int($tenantId) || $tenantId <= 0) {
|
|
return collect();
|
|
}
|
|
|
|
return self::shellVisibleQueryForTenantId($tenantId)
|
|
->limit(max(1, $limit))
|
|
->get();
|
|
}
|
|
|
|
public static function countForTenantId(?int $tenantId): int
|
|
{
|
|
if (! is_int($tenantId) || $tenantId <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
return self::queryForTenantId($tenantId)->count();
|
|
}
|
|
|
|
public static function shellVisibleCountForTenantId(?int $tenantId): int
|
|
{
|
|
if (! is_int($tenantId) || $tenantId <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
return self::shellVisibleQueryForTenantId($tenantId)->count();
|
|
}
|
|
|
|
public static function existForTenant(Tenant $tenant): bool
|
|
{
|
|
return self::existForTenantId((int) $tenant->getKey());
|
|
}
|
|
|
|
public static function existForTenantId(?int $tenantId): bool
|
|
{
|
|
if (! is_int($tenantId) || $tenantId <= 0) {
|
|
return false;
|
|
}
|
|
|
|
return OperationRun::query()
|
|
->where('tenant_id', $tenantId)
|
|
->healthyActive()
|
|
->exists();
|
|
}
|
|
|
|
public static function pollingIntervalForTenant(?Tenant $tenant): ?string
|
|
{
|
|
return $tenant instanceof Tenant
|
|
? self::pollingIntervalForTenantId((int) $tenant->getKey())
|
|
: null;
|
|
}
|
|
|
|
public static function pollingIntervalForTenantId(?int $tenantId): ?string
|
|
{
|
|
return self::existForTenantId($tenantId) ? '10s' : null;
|
|
}
|
|
}
|