Skip to content

Commit 29b7a8e

Browse files
basic workflow:wait fixes
1 parent a5ee59b commit 29b7a8e

File tree

1 file changed

+106
-51
lines changed

1 file changed

+106
-51
lines changed

src/Commands/Workflow/WaitCommand.php

Lines changed: 106 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Pantheon\Terminus\Commands\TerminusCommand;
66
use Pantheon\Terminus\Site\SiteAwareInterface;
77
use Pantheon\Terminus\Site\SiteAwareTrait;
8+
use Pantheon\Terminus\Exceptions\TerminusException;
89

910
/**
1011
* Class AwaitCommand.
@@ -40,13 +41,35 @@ public function workflowWait(
4041
]
4142
) {
4243
list($site, $env) = $this->getSiteEnv($site_env_id);
44+
if (!$site instanceof \Pantheon\Terminus\Models\Site) {
45+
throw new TerminusException(
46+
'Site {site} does not exist.',
47+
['site' => $site_env_id]
48+
);
49+
}
50+
else {
51+
$this->log()->notice('Waiting for workflow on site {site} environment {env}.', [
52+
'site' => $site->getName(),
53+
'env' => $site_env_id,
54+
]);
55+
}
56+
// print_r($site);
57+
if (!$env) {
58+
throw new TerminusException(
59+
'Environment {env} does not exist for site {site}.',
60+
['env' => $site_env_id, 'site' => $site->getName()]
61+
);
62+
}
63+
else {
64+
$this->log()->notice('Waiting for workflow on environment {env}.', ['env' => $env->getName()]);
65+
}
4366
$env_name = $env->getName();
4467

4568
$startTime = $options['start'];
4669
if (!$startTime) {
4770
$startTime = time() - 60;
4871
}
49-
if (!empty($options['target_commit'])) {
72+
if (!empty($options['commit'])) {
5073
$this->waitForCommit($startTime, $site, $env_name, $options['commit'], $options['max']);
5174
return;
5275
}
@@ -61,73 +84,96 @@ protected function waitForWorkflow(
6184
$maxWaitInSeconds = 180,
6285
$maxNotFoundAttempts = null
6386
) {
87+
$workflow = null;
6488
if (empty($expectedWorkflowDescription)) {
6589
$expectedWorkflowDescription = "Sync code on $env_name";
6690
}
6791

68-
$startWaiting = time();
69-
$firstWorkflowDescription = null;
70-
$notFoundAttempts = 0;
92+
$current_time = time();
93+
if ($maxWaitInSeconds > 0) {
94+
$end_time = $current_time + $maxWaitInSeconds;
95+
} else {
96+
$end_time = 0;
97+
}
98+
$not_found_attempts = 0;
7199
$workflows = $site->getWorkflows();
72100

73-
while (true) {
101+
do {
102+
$current_time = time();
103+
if ($maxNotFoundAttempts && $not_found_attempts === $maxNotFoundAttempts) {
104+
throw new TerminusException(
105+
"Attempted '{max}' times, giving up waiting for workflow to be found",
106+
['max' => $maxNotFoundAttempts]
107+
);
108+
}
109+
110+
// Check if the timeout has been reached and throw an exception if so.
111+
if ($end_time > 0 && $current_time >= $end_time) {
112+
throw new TerminusException(
113+
'Workflow timed out after {timeout} seconds.',
114+
['timeout' => $maxWaitInSeconds]
115+
);
116+
}
74117
$site = $this->getSiteById($site->id);
75-
// Refresh env on each interation.
76-
$index = 0;
77118
$workflows->reset();
119+
$workflows->setData();
78120
$workflow_items = $workflows->fetch(['paged' => false,])->all();
79-
$found = false;
80-
foreach ($workflow_items as $workflow) {
81-
$workflowCreationTime = $workflow->get('created_at');
82-
83-
$workflowDescription = str_replace('"', '', $workflow->get('description'));
84-
if ($index === 0) {
85-
$firstWorkflowDescription = $workflowDescription;
86-
}
87-
$index++;
88-
89-
if ($workflowCreationTime < $startTime) {
121+
foreach ($workflow_items as $current_workflow) {
122+
$workflow_created = $current_workflow->get('created_at');
123+
if ($workflow_created < $startTime) {
90124
// We already passed the start time.
91125
break;
92126
}
93-
94-
if (($expectedWorkflowDescription === $workflowDescription)) {
95-
$workflow->fetch();
127+
$workflow_description = str_replace('"', '', $current_workflow->get('description'));
128+
if (($expectedWorkflowDescription === $workflow_description)) {
129+
$current_workflow->fetch();
96130
$this->log()->notice(
97131
"Workflow '{current}' {status}.",
98-
['current' => $workflowDescription, 'status' => $workflow->getStatus()]
99-
);
100-
$found = true;
101-
if ($workflow->isSuccessful()) {
102-
$this->log()->notice("Workflow succeeded");
103-
return;
104-
}
105-
}
106-
}
107-
if (!$found) {
108-
$notFoundAttempts++;
109-
$this->log()->notice(
110-
"Current workflow is '{current}'; waiting for '{expected}'",
111-
['current' => $firstWorkflowDescription, 'expected' => $expectedWorkflowDescription]
112-
);
113-
if ($maxNotFoundAttempts && $notFoundAttempts === $maxNotFoundAttempts) {
114-
$this->log()->warning(
115-
"Attempted '{max}' times, giving up waiting for workflow to be found",
116-
['max' => $maxNotFoundAttempts]
132+
['current' => $workflow_description, 'status' => $current_workflow->getStatus()]
117133
);
134+
$workflow = $current_workflow;
118135
break;
119136
}
120137
}
121-
// Wait a bit, then spin some more
138+
if ($workflow) {
139+
$this->log()->debug("Workflow found: {workflow}", ['workflow' => $workflow_description]);
140+
break;
141+
}
142+
143+
$not_found_attempts++;
122144
sleep(5);
123-
if (time() - $startWaiting >= $maxWaitInSeconds) {
124-
$this->log()->warning(
125-
"Waited '{max}' seconds, giving up waiting for workflow to finish",
126-
['max' => $maxWaitInSeconds]
145+
} while (empty($workflow));
146+
147+
// If we get here, we have a workflow that is not finished.
148+
// We need to wait for it to finish.
149+
// At this point, we may have already spent some time waiting for the workflow to be found,
150+
// let's be forgiving and wait for the whole time again.
151+
$retry_interval = $this->getConfig()->get('workflow_polling_delay_ms', 5000);
152+
if ($retry_interval < 1000) {
153+
// The API will not allow polling faster than once per second.
154+
$retry_interval = 1000;
155+
}
156+
$current_time = time();
157+
if ($maxWaitInSeconds > 0) {
158+
$end_time = $current_time + $maxWaitInSeconds;
159+
} else {
160+
$end_time = 0;
161+
}
162+
do {
163+
if ($end_time > 0 && $current_time >= $end_time) {
164+
throw new TerminusException(
165+
'Workflow timed out after {timeout} seconds.',
166+
['timeout' => $maxWaitInSeconds]
127167
);
128-
break;
129168
}
169+
$workflow->fetch();
170+
usleep($retry_interval * 1000);
171+
$current_time = time();
172+
} while (!$workflow->isFinished());
173+
if (!$workflow->isSuccessful()) {
174+
throw new TerminusException($workflow->getMessage());
130175
}
176+
$this->log()->notice("Workflow succeeded");
131177
}
132178

133179
/**
@@ -144,7 +190,7 @@ public function waitForCommit(
144190
$wfl = null;
145191
$wflc = $site->getWorkflowLogs();
146192
if (!$wflc instanceof WorkflowLogsCollection) {
147-
throw new TerminusException('Workflow logs could not be retrieved for site: {site}', ['site' => $site_id,]);
193+
throw new TerminusException('Workflow logs could not be retrieved for site: {site}', ['site' => $site->id,]);
148194
}
149195

150196
// Remove workflows that are not for the environment $env_name.
@@ -155,21 +201,30 @@ public function waitForCommit(
155201
'target_commit' => $target_commit,
156202
]);
157203

204+
$current_time = time();
205+
if ($maxWaitInSeconds > 0) {
206+
$end_time = $current_time + $maxWaitInSeconds;
207+
} else {
208+
$end_time = 0;
209+
}
210+
158211
// If we didn't find a workflow, then we need to wait for one to be created
159212
if (!$wfl instanceof WorkflowLog) {
160213
// sleep to give the workflow time to be created
161214
sleep($this->getConfig()->get('refresh_workflow_delay', 30));
162215
$wfl = $wflc->fetch()->findLatestFromOptionsArray([
163216
'target_commit' => $target_commit,
164217
]);
165-
if ($startTime->diff(new \DateTime())->s > $options['max']) {
166-
throw new TerminusException('Exceeded maximum wait time of {max} seconds.', ['max' => $options['max']]);
218+
$current_time = time();
219+
if ($end_time > 0 && $current_time >= $end_time) {
220+
throw new TerminusException('Exceeded maximum wait time of {max} seconds.', ['max' => $maxWaitInSeconds]);
167221
}
168222
}
169223

170224
while (!$wfl->isFinished()) {
171-
if ($startTime->diff(new \DateTime())->s > $options['max']) {
172-
throw new TerminusException('Exceeded maximum wait time of {max} seconds.', ['max' => $options['max']]);
225+
$current_time = time();
226+
if ($end_time > 0 && $current_time >= $end_time) {
227+
throw new TerminusException('Exceeded maximum wait time of {max} seconds.', ['max' => $maxWaitInSeconds]);
173228
}
174229
$this->log()->notice('Waiting for workflow {id} to complete.', ['id' => $wfl->id,]);
175230
sleep($this->getConfig()->get('refresh_workflow_delay', 30));

0 commit comments

Comments
 (0)