@steedos-labs/plugin-workflow 3.0.0-beta.29 → 3.0.0-beta.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/main/default/client/instance.client.js +2 -2
- package/main/default/manager/import.js +16 -1
- package/main/default/manager/push_manager.js +14 -6
- package/main/default/methods/trace_approve_cc.js +568 -0
- package/main/default/objectTranslations/instances.en/instances.en.objectTranslation.yml +212 -0
- package/main/default/objectTranslations/instances.zh-CN/instances.zh-CN.objectTranslation.yml +209 -0
- package/main/default/objects/flows/buttons/newexport.button.yml +1 -1
- package/main/default/objects/flows/buttons/newimport.button.yml +2 -1
- package/main/default/objects/flows/flows.object.yml +1 -0
- package/main/default/objects/instances/buttons/instance_cc.button.yml +1 -1
- package/main/default/objects/instances/buttons/instance_distribute.button.yml +3 -2
- package/main/default/objects/instances/buttons/instance_forward.button.yml +1 -1
- package/main/default/objects/instances/buttons/instance_reassign.button.yml +1 -16
- package/main/default/objects/instances/buttons/instance_relocate.button.yml +1 -1
- package/main/default/objects/instances/buttons/instance_retrieve.button.yml +106 -2
- package/main/default/objects/instances/buttons/instance_save.button.yml +1 -1
- package/main/default/objects/instances/listviews/monitor.listview.yml +0 -1
- package/main/default/pages/instance_tasks_list.page.amis.json +6 -99
- package/main/default/pages/instances_list.page.amis.json +6 -100
- package/main/default/routes/api_cc.router.js +5 -12
- package/main/default/routes/api_flow_permission.router.js +7 -2
- package/main/default/routes/api_workflow_instance_return.router.js +164 -167
- package/main/default/routes/api_workflow_reassign.router.js +200 -196
- package/main/default/routes/api_workflow_relocate.router.js +1 -1
- package/main/default/routes/api_workflow_retrieve.router.js +246 -237
- package/main/default/routes/export.router.js +5 -4
- package/main/default/routes/flow_form_design.ejs +2 -0
- package/main/default/routes/import.router.js +6 -7
- package/main/default/triggers/amis_form_design.trigger.js +1 -1
- package/main/default/utils/designerManager.js +1 -0
- package/package.json +3 -2
- package/package.service.js +20 -6
- package/src/webhook_queue.js +283 -0
- package/main/default/manager/index.js +0 -23
package/package.service.js
CHANGED
|
@@ -5,6 +5,7 @@ const packageLoader = require('@steedos/service-package-loader');
|
|
|
5
5
|
|
|
6
6
|
const rests = require('./src/rests');
|
|
7
7
|
const InstanceRecordQueue = require('./src/instance_record_queue')
|
|
8
|
+
const WebhookQueue = require('./src/webhook_queue')
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @typedef {import('moleculer').Context} Context Moleculer's Context
|
|
@@ -124,12 +125,25 @@ module.exports = {
|
|
|
124
125
|
* Service started lifecycle event handler
|
|
125
126
|
*/
|
|
126
127
|
async started(ctx) {
|
|
127
|
-
if((process.env.STEEDOS_CRON_ENABLED === true || process.env.STEEDOS_CRON_ENABLED === 'true')
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
if((process.env.STEEDOS_CRON_ENABLED === true || process.env.STEEDOS_CRON_ENABLED === 'true')){
|
|
129
|
+
|
|
130
|
+
if (process.env.STEEDOS_CRON_INSTANCERECORDQUEUE_INTERVAL) {
|
|
131
|
+
InstanceRecordQueue.Configure({
|
|
132
|
+
sendInterval: process.env.STEEDOS_CRON_INSTANCERECORDQUEUE_INTERVAL,
|
|
133
|
+
sendBatchSize: 10,
|
|
134
|
+
keepDocs: true
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// webhooks 流程触发器 队列
|
|
139
|
+
if (process.env.STEEDOS_CRON_WEBHOOKQUEUE_INTERVAL) {
|
|
140
|
+
await WebhookQueue.Configure({
|
|
141
|
+
sendInterval: process.env.STEEDOS_CRON_WEBHOOKQUEUE_INTERVAL,
|
|
142
|
+
sendBatchSize: 10,
|
|
143
|
+
keepDocs: false
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
133
147
|
}
|
|
134
148
|
},
|
|
135
149
|
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @Author: 孙浩林 sunhaolin@steedos.com
|
|
3
|
+
* @Date: 2025-10-09 15:07:29
|
|
4
|
+
* @LastEditors: 孙浩林 sunhaolin@steedos.com
|
|
5
|
+
* @LastEditTime: 2025-10-10 11:43:04
|
|
6
|
+
* @FilePath: /steedos-plugins/steedos-packages/plugin-workflow/src/webhook_queue.js
|
|
7
|
+
* @Description:
|
|
8
|
+
*/
|
|
9
|
+
const _ = require("lodash");
|
|
10
|
+
const axios = require('axios');
|
|
11
|
+
|
|
12
|
+
const { getCollection } = require("../main/default/utils/collection");
|
|
13
|
+
|
|
14
|
+
const WebhookQueue = {};
|
|
15
|
+
|
|
16
|
+
WebhookQueue.send = async function (options) {
|
|
17
|
+
var currentUser = '<SERVER>'
|
|
18
|
+
var webhook = _.extend({
|
|
19
|
+
createdAt: new Date(),
|
|
20
|
+
createdBy: currentUser
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
webhook.webhook = _.pick(options, ['instance', 'current_approve', 'payload_url', 'content_type', 'action', 'from_user', 'to_users']);
|
|
24
|
+
|
|
25
|
+
webhook.sent = false;
|
|
26
|
+
webhook.sending = 0;
|
|
27
|
+
|
|
28
|
+
return await WebhookQueue.collection.insert(webhook);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
var isConfigured = false;
|
|
32
|
+
var sendWorker = async function (task, interval) {
|
|
33
|
+
|
|
34
|
+
if (WebhookQueue.debug) {
|
|
35
|
+
console.log('WebhookQueue: Send worker started, using interval: ' + interval);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return setInterval(async function () {
|
|
39
|
+
try {
|
|
40
|
+
await task();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (WebhookQueue.debug) {
|
|
43
|
+
console.log('WebhookQueue: Error while sending: ' + error.message);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}, interval);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
options: {
|
|
51
|
+
// Controls the sending interval
|
|
52
|
+
sendInterval: Match.Optional(Number),
|
|
53
|
+
// Controls the sending batch size per interval
|
|
54
|
+
sendBatchSize: Match.Optional(Number),
|
|
55
|
+
// Allow optional keeping notifications in collection
|
|
56
|
+
keepWebhooks: Match.Optional(Boolean)
|
|
57
|
+
}
|
|
58
|
+
*/
|
|
59
|
+
WebhookQueue.Configure = async function (options) {
|
|
60
|
+
WebhookQueue.collection = await getCollection('_webhook_queue');
|
|
61
|
+
|
|
62
|
+
var self = this;
|
|
63
|
+
options = _.extend({
|
|
64
|
+
sendTimeout: 60000, // Timeout period for webhook send
|
|
65
|
+
}, options);
|
|
66
|
+
|
|
67
|
+
// Block multiple calls
|
|
68
|
+
if (isConfigured) {
|
|
69
|
+
throw new Error('WebhookQueue.Configure should not be called more than once!');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
isConfigured = true;
|
|
73
|
+
|
|
74
|
+
// Add debug info
|
|
75
|
+
if (WebhookQueue.debug) {
|
|
76
|
+
console.log('WebhookQueue.Configure', options);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
self.sendWebhook = async function (webhook) {
|
|
80
|
+
if (WebhookQueue.debug) {
|
|
81
|
+
console.log("sendWebhook");
|
|
82
|
+
console.log(webhook);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const response = await axios({
|
|
87
|
+
method: 'post',
|
|
88
|
+
url: webhook.webhook.payload_url,
|
|
89
|
+
headers: {
|
|
90
|
+
"Content-Type": webhook.webhook.content_type
|
|
91
|
+
},
|
|
92
|
+
data: {
|
|
93
|
+
instance: webhook.webhook.instance,
|
|
94
|
+
current_approve: webhook.webhook.current_approve,
|
|
95
|
+
action: webhook.webhook.action,
|
|
96
|
+
from_user: webhook.webhook.from_user,
|
|
97
|
+
to_users: webhook.webhook.to_users
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (!options.keepWebhooks) {
|
|
102
|
+
// Pr. Default we will remove webhooks
|
|
103
|
+
await WebhookQueue.collection.remove({
|
|
104
|
+
_id: webhook._id,
|
|
105
|
+
errMsg: {
|
|
106
|
+
$exists: false
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
// Update the webhook
|
|
111
|
+
await WebhookQueue.collection.updateOne({
|
|
112
|
+
_id: webhook._id
|
|
113
|
+
}, {
|
|
114
|
+
$set: {
|
|
115
|
+
// Mark as sent
|
|
116
|
+
sent: true,
|
|
117
|
+
// Set the sent date
|
|
118
|
+
sentAt: new Date(),
|
|
119
|
+
// Not being sent anymore
|
|
120
|
+
sending: 0
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error(error);
|
|
127
|
+
await WebhookQueue.collection.updateOne({
|
|
128
|
+
_id: webhook._id
|
|
129
|
+
}, {
|
|
130
|
+
$set: {
|
|
131
|
+
// error message
|
|
132
|
+
errMsg: error
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Universal send function
|
|
140
|
+
var _querySend = async function (options) {
|
|
141
|
+
|
|
142
|
+
if (self.sendWebhook) {
|
|
143
|
+
await self.sendWebhook(options);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
webhook: [options._id]
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
self.serverSend = async function (options) {
|
|
152
|
+
options = options || {};
|
|
153
|
+
return await _querySend(options);
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
// This interval will allow only one webhook to be sent at a time, it
|
|
158
|
+
// will check for new webhooks at every `options.sendInterval`
|
|
159
|
+
// (default interval is 15000 ms)
|
|
160
|
+
//
|
|
161
|
+
// It looks in webhooks collection to see if theres any pending
|
|
162
|
+
// webhooks, if so it will try to reserve the pending webhook.
|
|
163
|
+
// If successfully reserved the send is started.
|
|
164
|
+
//
|
|
165
|
+
// If webhook.query is type string, it's assumed to be a json string
|
|
166
|
+
// version of the query selector. Making it able to carry `$` properties in
|
|
167
|
+
// the mongo collection.
|
|
168
|
+
//
|
|
169
|
+
// Pr. default webhooks are removed from the collection after send have
|
|
170
|
+
// completed. Setting `options.keepWebhooks` will update and keep the
|
|
171
|
+
// webhook eg. if needed for historical reasons.
|
|
172
|
+
//
|
|
173
|
+
// After the send have completed a "send" event will be emitted with a
|
|
174
|
+
// status object containing webhook id and the send result object.
|
|
175
|
+
//
|
|
176
|
+
var isSendingWebhook = false;
|
|
177
|
+
|
|
178
|
+
if (options.sendInterval !== null) {
|
|
179
|
+
|
|
180
|
+
// This will require index since we sort webhooks by createdAt
|
|
181
|
+
WebhookQueue.collection.createIndex({
|
|
182
|
+
createdAt: 1
|
|
183
|
+
});
|
|
184
|
+
WebhookQueue.collection.createIndex({
|
|
185
|
+
sent: 1
|
|
186
|
+
});
|
|
187
|
+
WebhookQueue.collection.createIndex({
|
|
188
|
+
sending: 1
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
var sendWebhook = async function (webhook) {
|
|
193
|
+
// Reserve webhook
|
|
194
|
+
var now = +new Date();
|
|
195
|
+
var timeoutAt = now + options.sendTimeout;
|
|
196
|
+
var reserved = await WebhookQueue.collection.updateOne({
|
|
197
|
+
_id: webhook._id,
|
|
198
|
+
sent: false, // xxx: need to make sure this is set on create
|
|
199
|
+
sending: {
|
|
200
|
+
$lt: now
|
|
201
|
+
}
|
|
202
|
+
}, {
|
|
203
|
+
$set: {
|
|
204
|
+
sending: timeoutAt,
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Make sure we only handle webhooks reserved by this
|
|
209
|
+
// instance
|
|
210
|
+
if (reserved) {
|
|
211
|
+
|
|
212
|
+
// Send the webhook
|
|
213
|
+
await WebhookQueue.serverSend(webhook);
|
|
214
|
+
|
|
215
|
+
} // Else could not reserve
|
|
216
|
+
}; // EO sendWebhook
|
|
217
|
+
|
|
218
|
+
await sendWorker(async function () {
|
|
219
|
+
|
|
220
|
+
if (isSendingWebhook) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
// Set send fence
|
|
224
|
+
isSendingWebhook = true;
|
|
225
|
+
|
|
226
|
+
var batchSize = options.sendBatchSize || 1;
|
|
227
|
+
|
|
228
|
+
var now = +new Date();
|
|
229
|
+
|
|
230
|
+
// Find webhooks that are not being or already sent
|
|
231
|
+
var pendingWebhooks = await WebhookQueue.collection.find({
|
|
232
|
+
$and: [
|
|
233
|
+
// Message is not sent
|
|
234
|
+
{
|
|
235
|
+
sent: false
|
|
236
|
+
},
|
|
237
|
+
// And not being sent by other instances
|
|
238
|
+
{
|
|
239
|
+
sending: {
|
|
240
|
+
$lt: now
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
// And no error
|
|
244
|
+
{
|
|
245
|
+
errMsg: {
|
|
246
|
+
$exists: false
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
}).sort({
|
|
251
|
+
createdAt: 1
|
|
252
|
+
}).limit(batchSize).toArray();
|
|
253
|
+
|
|
254
|
+
for (const webhook of pendingWebhooks) {
|
|
255
|
+
try {
|
|
256
|
+
await sendWebhook(webhook);
|
|
257
|
+
} catch (error) {
|
|
258
|
+
console.error(error.stack);
|
|
259
|
+
console.log('WebhookQueue: Could not send doc id: "' + webhook._id + '", Error: ' + error.message);
|
|
260
|
+
await WebhookQueue.collection.updateOne({
|
|
261
|
+
_id: webhook._id
|
|
262
|
+
}, {
|
|
263
|
+
$set: {
|
|
264
|
+
// error message
|
|
265
|
+
errMsg: error.message
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}; // EO forEach
|
|
270
|
+
|
|
271
|
+
// Remove the send fence
|
|
272
|
+
isSendingWebhook = false;
|
|
273
|
+
}, options.sendInterval || 15000); // Default every 15th sec
|
|
274
|
+
|
|
275
|
+
} else {
|
|
276
|
+
if (WebhookQueue.debug) {
|
|
277
|
+
console.log('WebhookQueue: Send server is disabled');
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
module.exports = WebhookQueue;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author: sunhaolin@hotoa.com
|
|
3
|
-
* @Date: 2022-12-20 14:49:06
|
|
4
|
-
* @LastEditors: sunhaolin@hotoa.com
|
|
5
|
-
* @LastEditTime: 2022-12-28 15:31:18
|
|
6
|
-
* @Description:
|
|
7
|
-
*/
|
|
8
|
-
require('./approve_manager')
|
|
9
|
-
require('./export')
|
|
10
|
-
require('./flow_manager')
|
|
11
|
-
require('./form_manager')
|
|
12
|
-
require('./get_handlers_manager')
|
|
13
|
-
require('./import')
|
|
14
|
-
require('./instance_manager')
|
|
15
|
-
require('./permission_manager')
|
|
16
|
-
require('./push_manager')
|
|
17
|
-
require('./step_manager')
|
|
18
|
-
require('./uuflow_manager')
|
|
19
|
-
require('./workflow_manager')
|
|
20
|
-
|
|
21
|
-
module.exports = {
|
|
22
|
-
instance_tasks_manager: require('./instance_tasks_manager')
|
|
23
|
-
}
|