Merge pull request #545 from automatisch/errors

Store and expose integration errors
This commit is contained in:
Ömer Faruk Aydın
2022-09-26 19:59:30 +03:00
committed by GitHub
7 changed files with 66 additions and 23 deletions

View File

@@ -19,7 +19,13 @@ export default class SearchTweets {
}; };
let response; let response;
const tweets: IJSONObject[] = []; const tweets: {
data: IJSONObject[];
error: IJSONObject | null;
} = {
data: [],
error: null,
};
do { do {
const params: IJSONObject = { const params: IJSONObject = {
@@ -47,10 +53,15 @@ export default class SearchTweets {
headers: { ...authHeader }, headers: { ...authHeader },
}); });
if (response.integrationError) {
tweets.error = response.integrationError;
return tweets;
}
if (response.data.meta.result_count > 0) { if (response.data.meta.result_count > 0) {
response.data.data.forEach((tweet: IJSONObject) => { response.data.data.forEach((tweet: IJSONObject) => {
if (!lastInternalId || Number(tweet.id) > Number(lastInternalId)) { if (!lastInternalId || Number(tweet.id) > Number(lastInternalId)) {
tweets.push(tweet); tweets.data.push(tweet);
} else { } else {
return; return;
} }
@@ -58,16 +69,6 @@ export default class SearchTweets {
} }
} while (response.data.meta.next_token && lastInternalId); } while (response.data.meta.next_token && lastInternalId);
if (response.data?.errors) {
const errorMessages = response.data.errors
.map((error: IJSONObject) => error.detail)
.join(' ');
throw new Error(
`Error occured while fetching user data: ${errorMessages}`
);
}
return tweets; return tweets;
} }
} }

View File

@@ -188,6 +188,7 @@ type ExecutionStep {
status: String status: String
dataIn: JSONObject dataIn: JSONObject
dataOut: JSONObject dataOut: JSONObject
errorDetails: JSONObject
createdAt: String createdAt: String
updatedAt: String updatedAt: String
} }

View File

@@ -1,6 +1,8 @@
import axios, { AxiosInstance } from 'axios'; import axios, { AxiosInstance, AxiosResponse } from 'axios';
import { IJSONObject, IHttpClientParams } from '@automatisch/types'; import { IJSONObject, IHttpClientParams } from '@automatisch/types';
type ExtendedAxiosResponse = AxiosResponse & { integrationError: IJSONObject };
export default class HttpClient { export default class HttpClient {
instance: AxiosInstance; instance: AxiosInstance;
@@ -8,13 +10,25 @@ export default class HttpClient {
this.instance = axios.create({ this.instance = axios.create({
baseURL: params.baseURL, baseURL: params.baseURL,
}); });
this.instance.interceptors.response.use(
(response) => response,
(error) => {
error.response.integrationError = error.response.data;
return error.response;
}
);
} }
async get(path: string, options?: IJSONObject) { async get(path: string, options?: IJSONObject) {
return await this.instance.get(path, options); return (await this.instance.get(path, options)) as ExtendedAxiosResponse;
} }
async post(path: string, body: IJSONObject | string, options?: IJSONObject) { async post(path: string, body: IJSONObject | string, options?: IJSONObject) {
return await this.instance.post(path, body, options); return (await this.instance.post(
path,
body,
options
)) as ExtendedAxiosResponse;
} }
} }

View File

@@ -33,9 +33,9 @@ class Processor {
const triggerStep = steps.find((step) => step.type === 'trigger'); const triggerStep = steps.find((step) => step.type === 'trigger');
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
let initialTriggerData = await this.getInitialTriggerData(triggerStep!); const initialTriggerData = await this.getInitialTriggerData(triggerStep!);
if (initialTriggerData.length === 0) { if (!initialTriggerData.error && initialTriggerData.data.length === 0) {
const lastInternalId = await this.flow.lastInternalId(); const lastInternalId = await this.flow.lastInternalId();
const executionData: Partial<Execution> = { const executionData: Partial<Execution> = {
@@ -52,12 +52,12 @@ class Processor {
return; return;
} }
if (this.testRun) { if (this.testRun && initialTriggerData.data.length > 0) {
initialTriggerData = [initialTriggerData[0]]; initialTriggerData.data = [initialTriggerData.data[0]];
} }
if (initialTriggerData.length > 1) { if (initialTriggerData.data.length > 1) {
initialTriggerData = initialTriggerData.sort( initialTriggerData.data = initialTriggerData.data.sort(
(item: IJSONObject, nextItem: IJSONObject) => { (item: IJSONObject, nextItem: IJSONObject) => {
return (item.id as number) - (nextItem.id as number); return (item.id as number) - (nextItem.id as number);
} }
@@ -66,7 +66,7 @@ class Processor {
const executions: Execution[] = []; const executions: Execution[] = [];
for await (const data of initialTriggerData) { for await (const data of initialTriggerData.data) {
const execution = await Execution.query().insert({ const execution = await Execution.query().insert({
flowId: this.flow.id, flowId: this.flow.id,
testRun: this.testRun, testRun: this.testRun,
@@ -118,6 +118,22 @@ class Processor {
} }
} }
if (initialTriggerData.error) {
const executionWithError = await Execution.query().insert({
flowId: this.flow.id,
testRun: this.testRun,
});
executions.push(executionWithError);
await executionWithError.$relatedQuery('executionSteps').insertAndFetch({
stepId: triggerStep.id,
status: 'failure',
dataIn: triggerStep.parameters,
errorDetails: initialTriggerData.error,
});
}
if (!this.testRun) return; if (!this.testRun) return;
const lastExecutionStepFromFirstExecution = await executions[0] const lastExecutionStepFromFirstExecution = await executions[0]
@@ -125,7 +141,11 @@ class Processor {
.orderBy('created_at', 'desc') .orderBy('created_at', 'desc')
.first(); .first();
return lastExecutionStepFromFirstExecution?.dataOut; if (lastExecutionStepFromFirstExecution.errorDetails) {
return lastExecutionStepFromFirstExecution.errorDetails;
} else {
return lastExecutionStepFromFirstExecution?.dataOut;
}
} }
async getInitialTriggerData(step: Step) { async getInitialTriggerData(step: Step) {

View File

@@ -26,6 +26,7 @@ export interface IExecutionStep {
step: IStep; step: IStep;
dataIn: IJSONObject; dataIn: IJSONObject;
dataOut: IJSONObject; dataOut: IJSONObject;
errorDetails: IJSONObject;
status: string; status: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;

View File

@@ -73,6 +73,7 @@ export default function ExecutionStep(props: ExecutionStepProps): React.ReactEle
<Tabs value={activeTabIndex} onChange={(event, tabIndex) => setActiveTabIndex(tabIndex)}> <Tabs value={activeTabIndex} onChange={(event, tabIndex) => setActiveTabIndex(tabIndex)}>
<Tab label="Data in" /> <Tab label="Data in" />
<Tab label="Data out" /> <Tab label="Data out" />
<Tab label="Error" />
<Tab label="Execution step" /> <Tab label="Execution step" />
</Tabs> </Tabs>
</Box> </Box>
@@ -86,6 +87,10 @@ export default function ExecutionStep(props: ExecutionStepProps): React.ReactEle
</TabPanel> </TabPanel>
<TabPanel value={activeTabIndex} index={2}> <TabPanel value={activeTabIndex} index={2}>
<JSONViewer data={executionStep.errorDetails} />
</TabPanel>
<TabPanel value={activeTabIndex} index={3}>
<JSONViewer data={(executionStep as unknown) as IJSONObject} /> <JSONViewer data={(executionStep as unknown) as IJSONObject} />
</TabPanel> </TabPanel>
</Content> </Content>

View File

@@ -14,6 +14,7 @@ export const GET_EXECUTION_STEPS = gql`
status status
dataIn dataIn
dataOut dataOut
errorDetails
createdAt createdAt
updatedAt updatedAt
step { step {