Skip to content

Commit 84da96a

Browse files
committed
feat: add cleanup for stale function executions
Adds a new interval task that marks executions stuck in 'processing' status for more than 30 minutes as 'failed' with a timeout error.
1 parent ce91b1a commit 84da96a

3 files changed

Lines changed: 54 additions & 1 deletion

File tree

.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ _APP_STATS_RESOURCES_INTERVAL=30
102102
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
103103
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
104104
_APP_INTERVAL_DOMAIN_VERIFICATION=60
105+
_APP_INTERVAL_CLEANUP_STALE_EXECUTIONS=300
105106
_APP_USAGE_STATS=enabled
106107
_APP_LOGGING_CONFIG=
107108
_APP_LOGGING_CONFIG_REALTIME=

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,7 @@ services:
880880
- _APP_DB_PASS
881881
- _APP_DATABASE_SHARED_TABLES
882882
- _APP_INTERVAL_DOMAIN_VERIFICATION
883+
- _APP_INTERVAL_CLEANUP_STALE_EXECUTIONS
883884

884885
appwrite-task-stats-resources:
885886
container_name: appwrite-task-stats-resources

src/Appwrite/Platform/Tasks/Interval.php

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,30 @@ public function __construct()
2424
$this
2525
->desc('Schedules tasks on regular intervals by publishing them to our queues')
2626
->inject('dbForPlatform')
27+
->inject('getProjectDB')
2728
->inject('queueForCertificates')
2829
->callback($this->action(...));
2930
}
3031

31-
public function action(Database $dbForPlatform, Certificate $queueForCertificates): void
32+
public function action(Database $dbForPlatform, callable $getProjectDB, Certificate $queueForCertificates): void
3233
{
3334
Console::title('Interval V1');
3435
Console::success(APP_NAME . ' interval process v1 has started');
3536

3637
$intervalDomainVerification = (int) System::getEnv('_APP_INTERVAL_DOMAIN_VERIFICATION', '60'); // 1 minute
38+
$intervalCleanupStaleExecutions = (int) System::getEnv('_APP_INTERVAL_CLEANUP_STALE_EXECUTIONS', '300'); // 5 minutes
3739

3840
\go(function () use ($dbForPlatform, $queueForCertificates, $intervalDomainVerification) {
3941
Console::loop(function () use ($dbForPlatform, $queueForCertificates) {
4042
$this->verifyDomain($dbForPlatform, $queueForCertificates);
4143
}, $intervalDomainVerification);
4244
});
45+
46+
\go(function () use ($dbForPlatform, $getProjectDB, $intervalCleanupStaleExecutions) {
47+
Console::loop(function () use ($dbForPlatform, $getProjectDB) {
48+
$this->cleanupStaleExecutions($dbForPlatform, $getProjectDB);
49+
}, $intervalCleanupStaleExecutions);
50+
});
4351
}
4452

4553
private function verifyDomain(Database $dbForPlatform, Certificate $queueForCertificates): void
@@ -72,4 +80,47 @@ private function verifyDomain(Database $dbForPlatform, Certificate $queueForCert
7280
->trigger();
7381
}
7482
}
83+
84+
private function cleanupStaleExecutions(Database $dbForPlatform, callable $getProjectDB): void
85+
{
86+
$time = DatabaseDateTime::now();
87+
$staleThreshold = DatabaseDateTime::addSeconds(new DateTime(), -1800); // 30 minutes ago
88+
89+
Console::info("[{$time}] Starting cleanup of stale executions");
90+
91+
$dbForPlatform->foreach(
92+
'projects',
93+
function (Document $project) use ($getProjectDB, $time, $staleThreshold) {
94+
try {
95+
$dbForProject = $getProjectDB($project);
96+
97+
$staleExecutions = $dbForProject->find('executions', [
98+
Query::equal('status', ['processing']),
99+
Query::lessThan('$createdAt', $staleThreshold),
100+
Query::limit(100),
101+
]);
102+
103+
if (\count($staleExecutions) === 0) {
104+
return;
105+
}
106+
107+
Console::info("[{$time}] Found " . \count($staleExecutions) . " stale executions in project {$project->getId()}");
108+
109+
foreach ($staleExecutions as $execution) {
110+
$execution->setAttribute('status', 'failed');
111+
$execution->setAttribute('errors', 'Execution timed out');
112+
$dbForProject->updateDocument('executions', $execution->getId(), $execution);
113+
}
114+
} catch (\Throwable $th) {
115+
Console::error("[{$time}] Failed to cleanup stale executions for project {$project->getId()}: " . $th->getMessage());
116+
}
117+
},
118+
[
119+
Query::equal('region', [System::getEnv('_APP_REGION', 'default')]),
120+
Query::limit(100),
121+
]
122+
);
123+
124+
Console::info("[{$time}] Completed cleanup of stale executions");
125+
}
75126
}

0 commit comments

Comments
 (0)