Skip to content

Commit

Permalink
Cancellable request improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mohr committed Jan 9, 2024
1 parent 7e583e4 commit f51c61d
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 41 deletions.
52 changes: 12 additions & 40 deletions src/components/JobPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import EventBusMixin from './EventBusMixin';
import WorkPanelMixin from './WorkPanelMixin';
import SyncButton from './SyncButton.vue';
import Utils from '../utils.js';
import { AbortController, Job } from '@openeo/js-client';
import { Job } from '@openeo/js-client';
import { cancellableRequest, showCancellableRequestError, CancellableRequestError } from './cancellableRequest';
const WorkPanelMixinInstance = WorkPanelMixin('jobs', 'batch job', 'batch jobs');
Expand All @@ -39,8 +40,7 @@ export default {
data() {
return {
watchers: {},
jobUpdater: null,
runId: 0
jobUpdater: null
};
},
mounted() {
Expand Down Expand Up @@ -145,48 +145,20 @@ export default {
await this.queueJob(job);
},
async executeProcess() {
let abortController = new AbortController();
let snotifyConfig = {
timeout: 0,
type: 'async',
buttons: [{
text: 'Cancel',
action: toast => {
abortController.abort();
this.$snotify.remove(toast.id, true);
}
}]
const callback = async (abortController) => {
const result = await this.connection.computeResult(this.process, null, null, abortController);
this.broadcast('viewSyncResult', result);
};
let toast;
try {
this.runId++;
let message = "A process is currently executed synchronously...";
let title = `Run #${this.runId}`;
let endlessPromise = () => new Promise(() => {}); // Pass a promise to snotify that never resolves as we manually close the toast
toast = this.$snotify.async(message, title, endlessPromise, snotifyConfig);
let result = await this.connection.computeResult(this.process, null, null, abortController);
this.broadcast('viewSyncResult', result);
} catch(error) {
if (axios.isCancel(error)) {
// Do nothing, we expected the cancellation
}
else if (typeof error.message === 'string' && Utils.isObject(error.response) && [400,500].includes(error.response.status)) {
this.broadcast('viewLogs', [{
id: error.id,
code: error.code,
level: 'error',
message: error.message,
links: error.links || []
}]);
Utils.error(this, "Synchronous processing failed. Please see the logs for details.", "Processing Error");
await cancellableRequest(this, callback, 'Run');
} catch (error) {
if (error instanceof CancellableRequestError) {
showCancellableRequestError(this, error);
}
else {
Utils.exception(this, error, "Server Error");
}
} finally {
if (toast) {
this.$snotify.remove(toast.id, true);
Utils.exception(this, error);
}
}
},
jobCreated(job) {
Expand Down
75 changes: 75 additions & 0 deletions src/components/cancellableRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { AbortController } from '@openeo/js-client';

export class CancellableRequestError extends Error {
constructor(message, title = null, cause = null, close = true, isError = true) {
super(message, {cause});
this.title = title;
this.close = close;
this.isError = isError;
}
}

export function showCancellableRequestError(vm, error) {
if (error instanceof CancellableRequestError) {
if (error.isError) {
Utils.error(vm, error.message, error.title);
}
else {
Utils.success(vm, error.message, error.title);
}
}
}

let runIds = {};
export async function cancellableRequest(vm, callback, entity) {
if (!runIds[entity]) {
runIds[entity] = 1;
}
else {
runIds[entity]++;
}

const abortController = new AbortController();
const snotifyConfig = Object.assign({}, vm.$config.snotifyDefaults, {
timeout: 0,
type: 'async',
buttons: [{
text: 'Cancel',
action: () => {
abortController.abort();
}
}]
});

let toast;
const toastTitle = `${entity} #${runIds[entity]}`;
try {
const message = `Processing in progress, please wait...`;
// Pass a promise to snotify that never resolves as we manually close the toast
const endlessPromise = () => new Promise(() => {});
toast = vm.$snotify.async(message, toastTitle, endlessPromise, snotifyConfig);

await callback(abortController);
} catch(error) {
if (axios.isCancel(error)) {
throw new CancellableRequestError(`Cancelled successfully`, toastTitle, error, false, false);
}
else if (typeof error.message === 'string' && Utils.isObject(error.response) && [400,500].includes(error.response.status)) {
vm.broadcast('viewLogs', [{
id: error.id,
code: error.code,
level: 'error',
message: error.message,
links: error.links || []
}]);
Utils.error(vm, `${entity} failed. Please see the logs for details.`, toastTitle);
}
else {
throw new CancellableRequestError(error.message, toastTitle, error, false);
}
} finally {
if (toast) {
vm.$snotify.remove(toast.id, true);
}
}
}
18 changes: 17 additions & 1 deletion src/components/modals/WizardModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import WizardStep from '../wizards/components/WizardStep.vue';
import Utils from '../../utils';
import Config from '../../../config';
import EventBusMixin from '../EventBusMixin';
import { CancellableRequestError } from '../cancellableRequest';
const wizards = Config.supportedWizards || [];
let components = {
Expand Down Expand Up @@ -248,7 +249,22 @@ export default {
else if (this.isLastStep) {
this.$refs.component.finish()
.then(this.close)
.catch(error => Utils.exception(this, error));
.catch(error => {
if (error instanceof CancellableRequestError) {
if (error.isError) {
Utils.exception(this, error, error.title);
}
else {
Utils.ok(this, error.message, error.title);
}
if (error.close) {
this.close();
}
}
else {
Utils.exception(this, error);
}
});
}
}
this.beforeTabChange(this.activeTabIndex, cb);
Expand Down

0 comments on commit f51c61d

Please sign in to comment.