Make it possible to define if workflow executions should be

saved or not
This commit is contained in:
Jan Oberhauser
2019-07-10 20:53:13 +02:00
parent e00bc83f1b
commit a17a376d13
8 changed files with 168 additions and 11 deletions

View File

@@ -22,6 +22,15 @@ module.exports = {
},
executions: {
// If a workflow executes all the data gets saved by default. This
// could be a problem when a workflow gets executed a lot and processes
// a lot of data. To not write the database full it is possible to
// not save the execution at all.
// Depending on if the execution did succeed or error a different
// save behaviour can be set.
saveDataErrorExecution: 'all', // Available options: all, none
saveDataSuccessExecution: 'all', // Available options: all, none
// If the executions of workflows which got started via the editor
// should be saved. By default they will not be saved as this runs
// are normally only for testing and debugging. This setting can

View File

@@ -189,6 +189,8 @@ export interface IN8nConfigNodes {
export interface IN8nUISettings {
endpointWebhook: string;
endpointWebhookTest: string;
saveDataErrorExecution: string;
saveDataSuccessExecution: string;
saveManualExecutions: boolean;
timezone: string;
urlBaseWebhook: string;

View File

@@ -73,6 +73,8 @@ class App {
testWebhooks: TestWebhooks.TestWebhooks;
endpointWebhook: string;
endpointWebhookTest: string;
saveDataErrorExecution: string;
saveDataSuccessExecution: string;
saveManualExecutions: boolean;
timezone: string;
activeExecutionsInstance: ActiveExecutions.ActiveExecutions;
@@ -83,6 +85,8 @@ class App {
this.endpointWebhook = config.get('urls.endpointWebhook') as string;
this.endpointWebhookTest = config.get('urls.endpointWebhookTest') as string;
this.saveDataErrorExecution = config.get('executions.saveDataErrorExecution') as string;
this.saveDataSuccessExecution = config.get('executions.saveDataSuccessExecution') as string;
this.saveManualExecutions = config.get('executions.saveManualExecutions') as boolean;
this.timezone = config.get('timezone') as string;
@@ -271,6 +275,14 @@ class App {
// Do not save the default timezone
delete newWorkflowData.settings.timezone;
}
if (newWorkflowData.settings.saveDataErrorExecution === 'DEFAULT') {
// Do not save when default got set
delete newWorkflowData.settings.saveDataErrorExecution;
}
if (newWorkflowData.settings.saveDataSuccessExecution === 'DEFAULT') {
// Do not save when default got set
delete newWorkflowData.settings.saveDataSuccessExecution;
}
if (newWorkflowData.settings.saveManualExecutions === 'DEFAULT') {
// Do not save when default got set
delete newWorkflowData.settings.saveManualExecutions;
@@ -900,6 +912,8 @@ class App {
return {
endpointWebhook: this.endpointWebhook,
endpointWebhookTest: this.endpointWebhookTest,
saveDataErrorExecution: this.saveDataErrorExecution,
saveDataSuccessExecution: this.saveDataSuccessExecution,
saveManualExecutions: this.saveManualExecutions,
timezone: this.timezone,
urlBaseWebhook: WebhookHelpers.getWebhookBaseUrl(),

View File

@@ -132,18 +132,26 @@ const hooks = (mode: WorkflowExecuteMode, workflowData: IWorkflowBase, workflowI
await workflowSavePromise;
}
// For now do not save manual executions
// TODO: Later that should be configurable. Think about what to do
// with the workflow.id when not saved yet or currently differes from saved version (save diff?!?!)
executeErrorWorkflow(workflowData, fullRunData, mode);
return;
}
// TODO: Should maybe have different log-modes like
// to save all data, only first input, only last node output, ....
// or depending on success to only save all on error to be
// able to start it again where it ended (but would then also have to save active data)
// Check config to know if execution should be saved or not
let saveDataErrorExecution = config.get('executions.saveDataErrorExecution') as string;
let saveDataSuccessExecution = config.get('executions.saveDataSuccessExecution') as string;
if (workflowInstance.settings !== undefined) {
saveDataErrorExecution = (workflowInstance.settings.saveDataErrorExecution as string) || saveDataErrorExecution;
saveDataSuccessExecution = (workflowInstance.settings.saveDataSuccessExecution as string) || saveDataSuccessExecution;
}
const workflowDidSucceed = !fullRunData.data.resultData.error;
if (workflowDidSucceed === true && saveDataSuccessExecution === 'none' ||
workflowDidSucceed === false && saveDataErrorExecution === 'none'
) {
executeErrorWorkflow(workflowData, fullRunData, mode);
return;
}
const fullExecutionData: IExecutionDb = {
data: fullRunData.data,
mode: fullRunData.mode,

View File

@@ -358,6 +358,8 @@ export interface IPushDataTestWebhook {
export interface IN8nUISettings {
endpointWebhook: string;
endpointWebhookTest: string;
saveDataErrorExecution: string;
saveDataSuccessExecution: string;
saveManualExecutions: boolean;
timezone: string;
urlBaseWebhook: string;
@@ -365,6 +367,8 @@ export interface IN8nUISettings {
export interface IWorkflowSettings extends IWorkflowSettingsWorkflow {
errorWorkflow?: string;
saveDataErrorExecution?: string;
saveDataSuccessExecution?: string;
saveManualExecutions?: boolean;
timezone?: string;
}

View File

@@ -40,6 +40,44 @@
</el-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Data Error Execution:
<el-tooltip class="setting-info" placement="top" effect="light">
<div slot="content" v-html="helpTexts.saveDataErrorExecution"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.saveDataErrorExecution" placeholder="Select Option" size="small" filterable>
<el-option
v-for="option of saveDataErrorExecutionOptions"
:key="option.key"
:label="option.value"
:value="option.key">
</el-option>
</el-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Data Success Execution:
<el-tooltip class="setting-info" placement="top" effect="light">
<div slot="content" v-html="helpTexts.saveDataSuccessExecution"></div>
<font-awesome-icon icon="question-circle" />
</el-tooltip>
</el-col>
<el-col :span="14" class="ignore-key-press">
<el-select v-model="workflowSettings.saveDataSuccessExecution" placeholder="Select Option" size="small" filterable>
<el-option
v-for="option of saveDataSuccessExecutionOptions"
:key="option.key"
:label="option.value"
:value="option.key">
</el-option>
</el-select>
</el-col>
</el-row>
<el-row>
<el-col :span="10" class="setting-name">
Save Manual Executions:
@@ -77,8 +115,9 @@ import { restApi } from '@/components/mixins/restApi';
import { genericHelpers } from '@/components/mixins/genericHelpers';
import { showMessage } from '@/components/mixins/showMessage';
import {
IWorkflowShortResponse,
IWorkflowDataUpdate,
IWorkflowSettings,
IWorkflowShortResponse,
} from '@/Interface';
import mixins from 'vue-typed-mixins';
@@ -98,12 +137,18 @@ export default mixins(
helpTexts: {
errorWorkflow: 'The workflow to run in case the current one fails.<br />To function correctly that workflow has to contain an "Error Trigger" node!',
timezone: 'The timezone in which the workflow should run. Gets for example used by "Cron" node.',
saveDataErrorExecution: 'If data data of executions should be saved in case they failed.',
saveDataSuccessExecution: 'If data data of executions should be saved in case they succeed.',
saveManualExecutions: 'If data data of executions should be saved when started manually from the editor.',
},
defaultValues: {
timezone: 'America/New_York',
saveDataErrorExecution: 'all',
saveDataSuccessExecution: 'all',
saveManualExecutions: false,
},
saveDataErrorExecutionOptions: [] as Array<{ key: string, value: string }>,
saveDataSuccessExecutionOptions: [] as Array<{ key: string, value: string }>,
saveManualOptions: [] as Array<{ key: string | boolean, value: string }>,
timezones: [] as Array<{ key: string, value: string }>,
workflowSettings: {},
@@ -124,11 +169,49 @@ export default mixins(
this.$emit('closeDialog');
return false;
},
async loadSaveDataErrorExecutionOptions () {
this.saveDataErrorExecutionOptions.length = 0;
this.saveDataErrorExecutionOptions.push.apply(
this.saveDataErrorExecutionOptions, [
{
key: 'DEFAULT',
value: 'Default - ' + (this.defaultValues.saveDataErrorExecution === 'all' ? 'Save' : 'Do not save'),
},
{
key: 'all',
value: 'Save',
},
{
key: 'none',
value: 'Do not save',
}
]
);
},
async loadSaveDataSuccessExecutionOptions () {
this.saveDataSuccessExecutionOptions.length = 0;
this.saveDataSuccessExecutionOptions.push.apply(
this.saveDataSuccessExecutionOptions, [
{
key: 'DEFAULT',
value: 'Default - ' + (this.defaultValues.saveDataSuccessExecution === 'all' ? 'Save' : 'Do not save'),
},
{
key: 'all',
value: 'Save',
},
{
key: 'none',
value: 'Do not save',
}
]
);
},
async loadSaveManualOptions () {
this.saveManualOptions.length = 0;
this.saveManualOptions.push({
key: 'DEFAULT',
value: 'Use default - ' + (this.defaultValues.saveManualExecutions === true ? 'Yes' : 'No'),
value: 'Default - ' + (this.defaultValues.saveManualExecutions === true ? 'Yes' : 'No'),
});
this.saveManualOptions.push({
key: true,
@@ -139,6 +222,7 @@ export default mixins(
value: 'No',
});
},
async loadTimezones () {
if (this.timezones.length !== 0) {
// Data got already loaded
@@ -196,12 +280,16 @@ export default mixins(
return;
}
this.defaultValues.saveDataErrorExecution = this.$store.getters.saveDataErrorExecution;
this.defaultValues.saveDataSuccessExecution = this.$store.getters.saveDataSuccessExecution;
this.defaultValues.saveManualExecutions = this.$store.getters.saveManualExecutions;
this.defaultValues.timezone = this.$store.getters.timezone;
this.isLoading = true;
const promises = [];
promises.push(this.loadWorkflows());
promises.push(this.loadSaveDataErrorExecutionOptions());
promises.push(this.loadSaveDataSuccessExecutionOptions());
promises.push(this.loadSaveManualOptions());
promises.push(this.loadTimezones());
@@ -216,6 +304,12 @@ export default mixins(
if (workflowSettings.timezone === undefined) {
workflowSettings.timezone = 'DEFAULT';
}
if (workflowSettings.saveDataErrorExecution === undefined) {
workflowSettings.saveDataErrorExecution = 'DEFAULT';
}
if (workflowSettings.saveDataSuccessExecution === undefined) {
workflowSettings.saveDataSuccessExecution = 'DEFAULT';
}
if (workflowSettings.saveManualExecutions === undefined) {
workflowSettings.saveManualExecutions = 'DEFAULT';
}
@@ -238,7 +332,16 @@ export default mixins(
this.isLoading = false;
return;
}
this.$store.commit('setWorkflowSettings', this.workflowSettings);
// Get the settings without the defaults set for local workflow settings
const localWorkflowSettings: IWorkflowSettings = {};
for (const key of Object.keys(this.workflowSettings)) {
if (this.workflowSettings[key] !== 'DEFAULT') {
localWorkflowSettings[key] = this.workflowSettings[key];
}
}
this.$store.commit('setWorkflowSettings', localWorkflowSettings);
this.isLoading = false;

View File

@@ -46,6 +46,8 @@ export const store = new Vuex.Store({
executingNode: '' as string | null,
executionWaitingForWebhook: false,
pushConnectionActive: false,
saveDataErrorExecution: 'all',
saveDataSuccessExecution: 'all',
saveManualExecutions: false,
timezone: 'America/New_York',
workflowExecutionData: null as IExecutionResponse | null,
@@ -458,6 +460,12 @@ export const store = new Vuex.Store({
Vue.set(state, 'endpointWebhookTest', endpointWebhookTest);
},
setSaveDataErrorExecution(state, newValue: string) {
Vue.set(state, 'saveDataErrorExecution', newValue);
},
setSaveDataSuccessExecution(state, newValue: string) {
Vue.set(state, 'saveDataSuccessExecution', newValue);
},
setSaveManualExecutions (state, saveManualExecutions: boolean) {
Vue.set(state, 'saveManualExecutions', saveManualExecutions);
},
@@ -551,6 +559,12 @@ export const store = new Vuex.Store({
return `${state.urlBaseWebhook}${state.endpointWebhookTest}`;
},
saveDataErrorExecution: (state): string => {
return state.saveDataErrorExecution;
},
saveDataSuccessExecution: (state): string => {
return state.saveDataSuccessExecution;
},
saveManualExecutions: (state): boolean => {
return state.saveManualExecutions;
},

View File

@@ -1674,9 +1674,12 @@ export default mixins(
},
async loadSettings (): Promise<void> {
const settings = await this.restApi().getSettings() as IN8nUISettings;
this.$store.commit('setUrlBaseWebhook', settings.urlBaseWebhook);
this.$store.commit('setEndpointWebhook', settings.endpointWebhook);
this.$store.commit('setEndpointWebhookTest', settings.endpointWebhookTest);
this.$store.commit('setSaveDataErrorExecution', settings.saveDataErrorExecution);
this.$store.commit('setSaveDataSuccessExecution', settings.saveDataSuccessExecution);
this.$store.commit('setSaveManualExecutions', settings.saveManualExecutions);
this.$store.commit('setTimezone', settings.timezone);
},