Skip to content

Commit 2c19b3d

Browse files
committed
Support better logging
1 parent 58a8d9b commit 2c19b3d

4 files changed

Lines changed: 135 additions & 39 deletions

File tree

‎ProcessMaker/Http/Controllers/Admin/ScriptExecutorController.php‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@
88

99
class ScriptExecutorController extends Controller
1010
{
11-
public function index(Request $request)
11+
public function index(Request $request, ScriptMicroserviceService $service)
1212
{
1313
if (!config('app.custom_executors')) {
1414
abort(404);
1515
}
1616

17+
$scriptMicroserviceEnabled = config('script-runner-microservice.enabled');
18+
1719
return view('admin.script-executors.index',
1820
[
19-
'script_microservice_enabled' => config('script-runner-microservice.enabled'),
21+
'script_microservice_enabled' => $scriptMicroserviceEnabled,
22+
'script_microservice_tenant_id' => $scriptMicroserviceEnabled
23+
? $service->getInstanceUuid()
24+
: null,
2025
]);
2126
}
2227
}

‎ProcessMaker/Http/Controllers/Api/ScriptExecutorController.php‎

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Auth\Access\AuthorizationException;
66
use Illuminate\Database\Eloquent\ModelNotFoundException;
7+
use Illuminate\Http\Client\RequestException;
78
use Illuminate\Http\Request;
89
use Illuminate\Validation\ValidationException;
910
use ProcessMaker\Enums\ScriptExecutorType;
@@ -124,7 +125,15 @@ public function store(Request $request, ScriptMicroserviceService $service)
124125
ScriptExecutorCreated::dispatch($scriptExecutor->getAttributes());
125126
BuildScriptExecutor::dispatch($scriptExecutor->id, $request->user()->id);
126127
} else {
127-
$service->createCustomExecutor($scriptExecutor);
128+
try {
129+
$service->createCustomExecutor($scriptExecutor);
130+
} catch (RequestException $e) {
131+
// The remote executor was rejected, so keeping the local record would leave
132+
// an executor that can never be built.
133+
$scriptExecutor->delete();
134+
135+
$this->throwMicroserviceError($e);
136+
}
128137
}
129138

130139
return ['status' => 'started', 'uuid' => $scriptExecutor->uuid, 'id' => $scriptExecutor->id];
@@ -189,7 +198,11 @@ public function update(Request $request, ScriptExecutor $scriptExecutor, ScriptM
189198
);
190199

191200
if (config('script-runner-microservice.enabled') && $scriptExecutor->type == ScriptExecutorType::Custom) {
192-
$service->updateCustomExecutor($scriptExecutor);
201+
try {
202+
$service->updateCustomExecutor($scriptExecutor);
203+
} catch (RequestException $e) {
204+
$this->throwMicroserviceError($e);
205+
}
193206
} else {
194207
if (!empty($scriptExecutor->getChanges())) {
195208
ScriptExecutorUpdated::dispatch($scriptExecutor->id, $original, $scriptExecutor->getChanges());
@@ -274,6 +287,28 @@ public function delete(Request $request, ScriptExecutor $scriptExecutor, ScriptM
274287
return ['status' => 'done'];
275288
}
276289

290+
/**
291+
* Report a script microservice rejection on the form, since the build itself
292+
* is only reported over the websocket channel.
293+
*
294+
* @param RequestException $e Failed script microservice response
295+
*
296+
* @return never
297+
*
298+
* @throws ValidationException|RequestException
299+
*/
300+
private function throwMicroserviceError(RequestException $e): never
301+
{
302+
if (!$e->response->clientError()) {
303+
throw $e;
304+
}
305+
306+
$detail = $e->response->json('detail');
307+
$message = is_string($detail) && $detail !== '' ? $detail : $e->getMessage();
308+
309+
throw ValidationException::withMessages(['language' => [$message]]);
310+
}
311+
277312
private function checkAuth($request)
278313
{
279314
if (!config('app.custom_executors')) {

‎resources/js/admin/script-executors/ScriptExecutors.vue‎

Lines changed: 90 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ export default {
252252
"filter",
253253
"permission",
254254
"script_microservice_enabled",
255+
"script_microservice_tenant_id",
255256
],
256257
data() {
257258
return {
@@ -271,7 +272,8 @@ export default {
271272
exitCode: 0,
272273
showDockerfile: false,
273274
loading: true,
274-
script_microservice_broadcast_uui: null,
275+
activeBuildUuid: null,
276+
pendingBuildEvents: [],
275277
276278
localLoadOnStart: true,
277279
orderBy: "language",
@@ -356,16 +358,15 @@ export default {
356358
}
357359
);
358360
}
361+
362+
if (this.script_microservice_enabled && this.script_microservice_tenant_id) {
363+
this.subscribeToTenantBuildChannel();
364+
}
359365
},
360366
watch: {
361367
commandOutput() {
362368
this.scrollToBottom();
363369
},
364-
script_microservice_broadcast_uui(newVal) {
365-
if (newVal) {
366-
this.subscribeToScriptMicroserviceChannel(newVal);
367-
}
368-
},
369370
},
370371
computed: {
371372
modalTitle() {
@@ -434,7 +435,13 @@ export default {
434435
},
435436
setErrors(errors) {
436437
this.status = "error";
437-
this.errors = errors.response.data.errors;
438+
this.errors = _.get(errors, "response.data.errors", {});
439+
const messages = Object.values(this.errors)
440+
.flat()
441+
.filter((message) => typeof message === "string" && message !== "");
442+
if (messages.length) {
443+
this.output(messages.join("\n") + "\n");
444+
}
438445
},
439446
doNotHideIfRunning(e) {
440447
if (this.isRunning) {
@@ -472,13 +479,15 @@ export default {
472479
save() {
473480
this.resetProcessInfo();
474481
this.status = "saving";
482+
this.activeBuildUuid = this.formData.uuid || null;
483+
this.pendingBuildEvents = [];
475484
if (this.formData.id) {
476485
const path = "/script-executors/" + this.formData.id;
477486
ProcessMaker.apiClient
478487
.put(path, this.formData)
479488
.then((result) => {
480489
this.status = _.get(result, "data.status", "error");
481-
this.script_microservice_broadcast_uui = result.data.uuid;
490+
this.setActiveBuildUuid(_.get(result, "data.uuid", this.formData.uuid));
482491
})
483492
.catch((e) => {
484493
this.setErrors(e);
@@ -489,9 +498,10 @@ export default {
489498
.post(path, this.formData)
490499
.then((result) => {
491500
this.status = _.get(result, "data.status", "error");
492-
this.script_microservice_broadcast_uui = result.data.uuid;
501+
this.setActiveBuildUuid(_.get(result, "data.uuid"));
493502
if (this.status === "started") {
494503
this.formData.id = result.data.id;
504+
this.formData.uuid = result.data.uuid;
495505
this.fetch(); // refresh the table (beneath the modal)
496506
}
497507
})
@@ -505,13 +515,17 @@ export default {
505515
},
506516
edit(row) {
507517
this.formData = _.cloneDeep(row);
518+
this.activeBuildUuid = row.uuid || null;
508519
this.$refs.edit.show();
509520
},
510521
reset() {
511522
this.formData = _.cloneDeep(this.emptyFormData);
512523
this.errors = {};
513524
this.showDockerfile = false;
514-
(this.status = "idle"), this.resetProcessInfo();
525+
this.status = "idle";
526+
this.activeBuildUuid = null;
527+
this.pendingBuildEvents = [];
528+
this.resetProcessInfo();
515529
},
516530
resetProcessInfo() {
517531
this.commandOutput = "";
@@ -550,31 +564,72 @@ export default {
550564
onAddToBundle(data) {
551565
this.$root.$emit('add-to-bundle', data);
552566
},
553-
subscribeToScriptMicroserviceChannel(name) {
554-
const channel = `build-image-${name}`;
555-
if (this.script_microservice_enabled) {
556-
// Subscribe to new channel
557-
window.ScriptMicroserviceEcho
558-
.channel(channel)
559-
.listenToAll((eventName, data) => {
560-
this.status = this.status === "idle" ? "starting" : this.status;
561-
switch (eventName) {
562-
case ".build-image":
563-
this.output(`${data}\n`);
564-
break;
565-
case ".build-finished":
566-
this.pidFile = null;
567-
this.exitCode = 0;
568-
this.status = "done";
569-
break;
570-
case ".build-error":
571-
this.output(data);
572-
this.pidFile = null;
573-
this.exitCode = 1;
574-
this.status = "done";
575-
break;
576-
}
577-
});
567+
subscribeToTenantBuildChannel() {
568+
if (!window.ScriptMicroserviceEcho) {
569+
return;
570+
}
571+
const channel = `tenant-${this.script_microservice_tenant_id}-builds`;
572+
window.ScriptMicroserviceEcho.channel(channel).listen(
573+
".executor-build",
574+
(data) => {
575+
this.handleExecutorBuildEvent(data);
576+
}
577+
);
578+
},
579+
setActiveBuildUuid(uuid) {
580+
if (!uuid) {
581+
return;
582+
}
583+
this.activeBuildUuid = uuid;
584+
const pending = this.pendingBuildEvents.filter(
585+
(event) => event.executor_id === uuid
586+
);
587+
this.pendingBuildEvents = [];
588+
pending.forEach((event) => this.applyExecutorBuildEvent(event));
589+
},
590+
handleExecutorBuildEvent(data) {
591+
if (!data || typeof data !== "object") {
592+
return;
593+
}
594+
if (!this.isRunning) {
595+
return;
596+
}
597+
if (!this.activeBuildUuid) {
598+
this.pendingBuildEvents.push(data);
599+
return;
600+
}
601+
if (data.executor_id !== this.activeBuildUuid) {
602+
return;
603+
}
604+
this.applyExecutorBuildEvent(data);
605+
},
606+
applyExecutorBuildEvent(data) {
607+
if (this.status === "saving") {
608+
this.status = "starting";
609+
} else if (this.status === "idle") {
610+
this.status = "starting";
611+
}
612+
613+
if (data.type === "status") {
614+
this.output(`[${data.phase}] ${data.message || ""}\n`);
615+
} else if (data.message) {
616+
const message = data.message.endsWith("\n")
617+
? data.message
618+
: `${data.message}\n`;
619+
this.output(message);
620+
}
621+
622+
if (data.phase === "completed" && data.type === "status") {
623+
this.pidFile = null;
624+
this.exitCode = 0;
625+
this.status = "done";
626+
return;
627+
}
628+
629+
if (data.phase === "error" || data.type === "error") {
630+
this.pidFile = null;
631+
this.exitCode = 1;
632+
this.status = "done";
578633
}
579634
},
580635
},

‎resources/views/admin/script-executors/index.blade.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
<div class="card card-body">
2020
<script-executors
2121
:script_microservice_enabled="@json($script_microservice_enabled)"
22+
script_microservice_tenant_id="{{$script_microservice_tenant_id}}"
2223
></script-executors>
2324
</div>
2425
</div>

0 commit comments

Comments
 (0)