diff --git a/app/config/collections.php b/app/config/collections.php index 0c8108fb58..d8f65da788 100644 --- a/app/config/collections.php +++ b/app/config/collections.php @@ -2148,6 +2148,17 @@ $collections = [ 'array' => false, 'filters' => [], ], + [ + '$id' => ID::custom('scheduleUpdatedAt'), // Used to fix duplicate executions bug. Can be removed once new queue library is used + 'type' => Database::VAR_DATETIME, + 'format' => '', + 'size' => 0, + 'signed' => false, + 'required' => false, + 'default' => null, + 'array' => false, + 'filters' => ['datetime'], + ], [ '$id' => ID::custom('schedulePrevious'), 'type' => Database::VAR_DATETIME, diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 606d8bfd1a..f42d1059e0 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -84,6 +84,7 @@ App::post('/v1/functions') 'deployment' => '', 'events' => $events, 'schedule' => $schedule, + 'scheduleUpdatedAt' => DateTime::now(), 'schedulePrevious' => null, 'scheduleNext' => null, 'timeout' => $timeout, @@ -445,6 +446,7 @@ App::put('/v1/functions/:functionId') $cron = (!empty($function->getAttribute('deployment')) && !empty($schedule)) ? new CronExpression($schedule) : null; $next = (!empty($function->getAttribute('deployment')) && !empty($schedule)) ? DateTime::format($cron->getNextRunDate()) : null; + $scheduleUpdatedAt = $schedule !== $original ? DateTime::now() : $function->getAttribute('scheduleUpdatedAt'); $enabled ??= $function->getAttribute('enabled', true); $function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [ @@ -452,6 +454,7 @@ App::put('/v1/functions/:functionId') 'name' => $name, 'events' => $events, 'schedule' => $schedule, + 'scheduleUpdatedAt' => $scheduleUpdatedAt, 'scheduleNext' => $next, 'timeout' => $timeout, 'enabled' => $enabled, diff --git a/app/workers/functions.php b/app/workers/functions.php index b7ef80a40b..31b74a11ca 100644 --- a/app/workers/functions.php +++ b/app/workers/functions.php @@ -129,7 +129,7 @@ class FunctionsV1 extends Worker break; case 'schedule': - $scheduleOriginal = $execution->getAttribute('scheduleOriginal', ''); + $functionOriginal = $function; /* * 1. Get Original Task * 2. Check for updates @@ -150,21 +150,25 @@ class FunctionsV1 extends Worker throw new Exception('Function not found (' . $function->getId() . ')'); } - if ($scheduleOriginal && $scheduleOriginal !== $function->getAttribute('schedule')) { // Schedule has changed from previous run, ignore this run. + if ($functionOriginal->getAttribute('schedule') !== $function->getAttribute('schedule')) { // Schedule has changed from previous run, ignore this run. + return; + } + + if ($functionOriginal->getAttribute('scheduleUpdatedAt') !== $function->getAttribute('scheduleUpdatedAt')) { // Double execution due to rapid cron changes, ignore this run. return; } $cron = new CronExpression($function->getAttribute('schedule')); $next = DateTime::format($cron->getNextRunDate()); - $function + $function = $function ->setAttribute('scheduleNext', $next) ->setAttribute('schedulePrevious', DateTime::now()); $function = $database->updateDocument( 'functions', $function->getId(), - $function->setAttribute('scheduleNext', $next) + $function ); $reschedule = new Func();