Skip to content
This repository was archived by the owner on Jul 28, 2020. It is now read-only.

Commit dc3f0c2

Browse files
authored
Merge pull request #60 from zenaton/scheduling_alfred
Scheduling with alfred and new syntax.
2 parents 05b8db7 + 0b85c2f commit dc3f0c2

File tree

14 files changed

+6749
-174
lines changed

14 files changed

+6749
-174
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
1515

1616
### Changed
1717

18+
- Changed scheduling requests that pass now through Alfred (GraphQL API).
19+
20+
- Changed scheduling syntax from `x.repeat("* * * * *").schedule()` to `x.shedule("* * * * *")`.
21+
1822
### Deprecated
1923

2024
### Removed

package-lock.json

Lines changed: 6504 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"dependencies": {
2929
"@babel/runtime": "7.3.1",
3030
"axios": "0.18.1",
31-
"cron-parser": "2.11.0",
31+
"graphql-request": "^1.8.2",
3232
"moment-timezone": "0.5.23",
3333
"uuid": "^3.3.2"
3434
},

src/async/Client.js

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const uuidv4 = require("uuid/v4");
22
const workflowManager = require("./Workflows/WorkflowManager");
33
const http = require("./Services/Http");
4+
const graphQL = require("./Services/GraphQL");
45
const serializer = require("./Services/Serializer");
56
const { version } = require("../infos");
67
const { init, credentials } = require("../client");
@@ -10,6 +11,8 @@ const ZENATON_WORKER_URL = "http://localhost";
1011
const DEFAULT_WORKER_PORT = 4001;
1112
const WORKER_API_VERSION = "v_newton";
1213

14+
const ZENATON_GATEWAY_URL = "https://gateway.zenaton.com/api";
15+
1316
const APP_ENV = "app_env";
1417
const APP_ID = "app_id";
1518
const API_TOKEN = "api_token";
@@ -25,7 +28,6 @@ const ATTR_INITIAL_LIB_VERSION = "initial_library_version";
2528
const ATTR_CODE_PATH_VERSION = "code_path_version";
2629
const ATTR_MODE = "mode";
2730
const ATTR_MAX_PROCESSING_TIME = "maxProcessingTime";
28-
const ATTR_SCHEDULING_CRON = "scheduling_cron";
2931

3032
const PROG = "Javascript";
3133
const INITIAL_LIB_VERSION = version;
@@ -113,6 +115,14 @@ module.exports = class Client {
113115
return `${host}${path}`;
114116
}
115117

118+
getGatewayUrl() {
119+
const host = process.env.ZENATON_GATEWAY_URL
120+
? process.env.ZENATON_GATEWAY_URL
121+
: ZENATON_GATEWAY_URL;
122+
123+
return host;
124+
}
125+
116126
/**
117127
* Start a task instance
118128
*/
@@ -136,19 +146,24 @@ module.exports = class Client {
136146
}
137147

138148
async startScheduledTask(task) {
139-
const url = this.getWorkerUrlNew("scheduling/tasks");
140-
141-
// schedule task
142-
const body = this.getBodyForTask(task);
143-
144-
const params = Object.assign(
145-
{
146-
[ATTR_SCHEDULING_CRON]: task.scheduling.cron,
149+
const endpoint = this.getGatewayUrl();
150+
const taskBody = this.getBodyForTask(task);
151+
const mutation = graphQL.mutations.createTaskSchedule;
152+
const variables = {
153+
createTaskScheduleInput: {
154+
intentId: taskBody[ATTR_INTENT_ID],
155+
environmentName: credentials.appEnv,
156+
cron: task.scheduling.cron,
157+
taskName: taskBody[ATTR_NAME],
158+
programmingLanguage: taskBody[ATTR_PROG].toUpperCase(),
159+
properties: taskBody[ATTR_DATA],
160+
codePathVersion: taskBody[ATTR_CODE_PATH_VERSION],
161+
initialLibraryVersion: taskBody[ATTR_INITIAL_LIB_VERSION],
147162
},
148-
this.getAppEnv(),
149-
);
163+
};
150164

151-
return http.post(url, body, { params });
165+
const res = await graphQL.request(endpoint, mutation, variables);
166+
return res.createTaskSchedule;
152167
}
153168

154169
/**
@@ -174,19 +189,25 @@ module.exports = class Client {
174189
}
175190

176191
async startScheduledWorkflow(flow) {
177-
const url = this.getWorkerUrlNew("scheduling/instances");
178-
179-
// schedule workflow
180-
const body = this.getBodyForWorkflow(flow);
181-
182-
const params = Object.assign(
183-
{
184-
[ATTR_SCHEDULING_CRON]: flow.scheduling.cron,
192+
const endpoint = this.getGatewayUrl();
193+
const workflowBody = this.getBodyForWorkflow(flow);
194+
const mutation = graphQL.mutations.createWorkflowSchedule;
195+
const variables = {
196+
createWorkflowScheduleInput: {
197+
intentId: workflowBody[ATTR_INTENT_ID],
198+
environmentName: credentials.appEnv,
199+
cron: flow.scheduling.cron,
200+
workflowName: workflowBody[ATTR_NAME],
201+
canonicalName: workflowBody[ATTR_CANONICAL] || workflowBody[ATTR_NAME],
202+
programmingLanguage: workflowBody[ATTR_PROG].toUpperCase(),
203+
properties: workflowBody[ATTR_DATA],
204+
codePathVersion: workflowBody[ATTR_CODE_PATH_VERSION],
205+
initialLibraryVersion: workflowBody[ATTR_INITIAL_LIB_VERSION],
185206
},
186-
this.getAppEnv(),
187-
);
207+
};
188208

189-
return http.post(url, body, { params });
209+
const res = await graphQL.request(endpoint, mutation, variables);
210+
return res.createWorkflowSchedule;
190211
}
191212

192213
/**

src/async/Engine/Engine.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,7 @@ module.exports = class Engine {
7373
? this.client.startWorkflow(job)
7474
: this.client.startTask(job);
7575

76-
await handler;
77-
78-
return undefined;
76+
return handler;
7977
});
8078

8179
// return results

src/async/Services/GraphQL.js

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
const { GraphQLClient } = require("graphql-request");
2+
const {
3+
ExternalZenatonError,
4+
InternalZenatonError,
5+
ZenatonError,
6+
} = require("../../Errors");
7+
const { credentials } = require("../../client");
8+
9+
function getError(err) {
10+
// Validation errors
11+
if (err.response && err.response.errors && err.response.errors.length > 0) {
12+
const message = err.response.errors
13+
.map((graphqlError) => {
14+
const path = graphqlError.path ? `(${graphqlError.path}) ` : "";
15+
const errorMessage = graphqlError.message || "Unknown error";
16+
return `${path}${errorMessage}`;
17+
})
18+
.join("\n");
19+
return new ExternalZenatonError(message);
20+
}
21+
22+
// Internal Server Error
23+
if (err.response && err.response.status >= 500) {
24+
return new InternalZenatonError(
25+
`Please contact Zenaton support - ${err.message}`,
26+
);
27+
}
28+
29+
return new ZenatonError(err.message);
30+
}
31+
32+
async function request(endpoint, query, variables) {
33+
try {
34+
const graphQLClient = new GraphQLClient(endpoint, {
35+
headers: {
36+
Accept: "application/json",
37+
"Content-Type": "application/json",
38+
"app-id": credentials.appId,
39+
"api-token": credentials.apiToken,
40+
},
41+
});
42+
43+
return graphQLClient.request(query, variables);
44+
} catch (err) {
45+
throw getError(err);
46+
}
47+
}
48+
49+
const mutations = {
50+
createWorkflowSchedule: `
51+
mutation ($createWorkflowScheduleInput: CreateWorkflowScheduleInput!) {
52+
createWorkflowSchedule(input: $createWorkflowScheduleInput) {
53+
schedule {
54+
id
55+
name
56+
cron
57+
insertedAt
58+
updatedAt
59+
target {
60+
... on WorkflowTarget {
61+
name
62+
type
63+
canonicalName
64+
programmingLanguage
65+
properties
66+
codePathVersion
67+
initialLibraryVersion
68+
}
69+
}
70+
}
71+
}
72+
}`,
73+
createTaskSchedule: `
74+
mutation ($createTaskScheduleInput: CreateTaskScheduleInput!) {
75+
createTaskSchedule(input: $createTaskScheduleInput) {
76+
schedule {
77+
id
78+
name
79+
cron
80+
insertedAt
81+
updatedAt
82+
target {
83+
... on TaskTarget {
84+
name
85+
type
86+
programmingLanguage
87+
properties
88+
codePathVersion
89+
initialLibraryVersion
90+
}
91+
}
92+
}
93+
}
94+
}`,
95+
};
96+
97+
module.exports.request = request;
98+
module.exports.mutations = mutations;

src/async/Services/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
module.exports.http = require("./Http");
2+
module.exports.graphQL = require("./GraphQL");
23
module.exports.serializer = require("./Serializer");
34
module.exports.Trait = require("./Trait");

src/async/Tasks/AbstractTask.js

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
const CronParser = require("cron-parser");
21
const TaskContext = require("../Runtime/Contexts/TaskContext");
3-
42
const Engine = require("../Engine/Engine");
53
const { ZenatonError } = require("../../Errors");
64

@@ -27,14 +25,24 @@ module.exports = class AbstractTask {
2725
}
2826

2927
// asynchronous execution within a workflow
30-
async schedule() {
28+
async schedule(cron) {
29+
if (typeof cron !== "string" || cron === "") {
30+
throw new ZenatonError(
31+
"Param passed to 'schedule' function must be a non empty string",
32+
);
33+
}
34+
35+
this.scheduling = this.scheduling || {};
36+
this.scheduling.cron = cron;
37+
3138
const result = await new Engine().dispatch([this]);
32-
return result[0].then(() => undefined);
39+
return result[0].then((res) => res);
3340
}
3441

3542
// asynchronous execution within a workflow
36-
async dispatch(...args) {
37-
return this.schedule(...args);
43+
async dispatch() {
44+
const result = await new Engine().dispatch([this]);
45+
return result[0].then(() => undefined);
3846
}
3947

4048
// synchronous execution within a workflow
@@ -43,27 +51,6 @@ module.exports = class AbstractTask {
4351
return result[0];
4452
}
4553

46-
repeat(cron) {
47-
if (typeof cron !== "string") {
48-
throw new ZenatonError(
49-
"Param passed to 'repeat' function must be a string",
50-
);
51-
}
52-
53-
try {
54-
CronParser.parseExpression(cron);
55-
} catch (err) {
56-
throw new ZenatonError(
57-
"Param passed to 'repeat' function is not a proper CRON expression",
58-
);
59-
}
60-
61-
this.scheduling = this.scheduling || {};
62-
this.scheduling.cron = cron;
63-
64-
return this;
65-
}
66-
6754
static methods() {
6855
return ["handle", "maxProcessingTime", "onFailureRetryDelay"];
6956
}

src/async/Workflows/AbstractWorkflow.js

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
const CronParser = require("cron-parser");
21
const WorkflowContext = require("../Runtime/Contexts/WorkflowContext");
3-
42
const Engine = require("../Engine/Engine");
53
const { ZenatonError } = require("../../Errors");
64

@@ -27,14 +25,24 @@ module.exports = class AbstractWorkflow {
2725
}
2826

2927
// asynchronous execution within a workflow
30-
async schedule() {
28+
async schedule(cron) {
29+
if (typeof cron !== "string" || cron === "") {
30+
throw new ZenatonError(
31+
"Param passed to 'schedule' function must be a non empty string",
32+
);
33+
}
34+
35+
this.scheduling = this.scheduling || {};
36+
this.scheduling.cron = cron;
37+
3138
const result = await new Engine().dispatch([this]);
32-
return result[0].then(() => undefined);
39+
return result[0].then((res) => res);
3340
}
3441

3542
// asynchronous execution within a workflow
36-
async dispatch(...args) {
37-
return this.schedule(...args);
43+
async dispatch() {
44+
const result = await new Engine().dispatch([this]);
45+
return result[0].then(() => undefined);
3846
}
3947

4048
// synchronous execution within a workflow
@@ -43,27 +51,6 @@ module.exports = class AbstractWorkflow {
4351
return result[0];
4452
}
4553

46-
repeat(cron) {
47-
if (typeof cron !== "string") {
48-
throw new ZenatonError(
49-
"Param passed to 'repeat' function must be a string",
50-
);
51-
}
52-
53-
try {
54-
CronParser.parseExpression(cron);
55-
} catch (err) {
56-
throw new ZenatonError(
57-
"Param passed to 'repeat' function is not a proper CRON expression",
58-
);
59-
}
60-
61-
this.scheduling = this.scheduling || {};
62-
this.scheduling.cron = cron;
63-
64-
return this;
65-
}
66-
6754
static methods() {
6855
return [
6956
"handle",

0 commit comments

Comments
 (0)