@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.
Files changed (34) hide show
  1. package/main/default/client/instance.client.js +2 -2
  2. package/main/default/manager/import.js +16 -1
  3. package/main/default/manager/push_manager.js +14 -6
  4. package/main/default/methods/trace_approve_cc.js +568 -0
  5. package/main/default/objectTranslations/instances.en/instances.en.objectTranslation.yml +212 -0
  6. package/main/default/objectTranslations/instances.zh-CN/instances.zh-CN.objectTranslation.yml +209 -0
  7. package/main/default/objects/flows/buttons/newexport.button.yml +1 -1
  8. package/main/default/objects/flows/buttons/newimport.button.yml +2 -1
  9. package/main/default/objects/flows/flows.object.yml +1 -0
  10. package/main/default/objects/instances/buttons/instance_cc.button.yml +1 -1
  11. package/main/default/objects/instances/buttons/instance_distribute.button.yml +3 -2
  12. package/main/default/objects/instances/buttons/instance_forward.button.yml +1 -1
  13. package/main/default/objects/instances/buttons/instance_reassign.button.yml +1 -16
  14. package/main/default/objects/instances/buttons/instance_relocate.button.yml +1 -1
  15. package/main/default/objects/instances/buttons/instance_retrieve.button.yml +106 -2
  16. package/main/default/objects/instances/buttons/instance_save.button.yml +1 -1
  17. package/main/default/objects/instances/listviews/monitor.listview.yml +0 -1
  18. package/main/default/pages/instance_tasks_list.page.amis.json +6 -99
  19. package/main/default/pages/instances_list.page.amis.json +6 -100
  20. package/main/default/routes/api_cc.router.js +5 -12
  21. package/main/default/routes/api_flow_permission.router.js +7 -2
  22. package/main/default/routes/api_workflow_instance_return.router.js +164 -167
  23. package/main/default/routes/api_workflow_reassign.router.js +200 -196
  24. package/main/default/routes/api_workflow_relocate.router.js +1 -1
  25. package/main/default/routes/api_workflow_retrieve.router.js +246 -237
  26. package/main/default/routes/export.router.js +5 -4
  27. package/main/default/routes/flow_form_design.ejs +2 -0
  28. package/main/default/routes/import.router.js +6 -7
  29. package/main/default/triggers/amis_form_design.trigger.js +1 -1
  30. package/main/default/utils/designerManager.js +1 -0
  31. package/package.json +3 -2
  32. package/package.service.js +20 -6
  33. package/src/webhook_queue.js +283 -0
  34. package/main/default/manager/index.js +0 -23
@@ -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') && process.env.STEEDOS_CRON_INSTANCERECORDQUEUE_INTERVAL){
128
- InstanceRecordQueue.Configure({
129
- sendInterval: process.env.STEEDOS_CRON_INSTANCERECORDQUEUE_INTERVAL,
130
- sendBatchSize: 10,
131
- keepDocs: true
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
- }