@budibase/backend-core 2.21.4 → 2.21.6
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/dist/index.js +249 -32
- package/dist/index.js.map +4 -4
- package/dist/index.js.meta.json +1 -1
- package/dist/package.json +4 -4
- package/dist/plugins.js.meta.json +1 -1
- package/dist/src/cache/base/index.d.ts +32 -2
- package/dist/src/cache/base/index.js +60 -1
- package/dist/src/cache/base/index.js.map +1 -1
- package/dist/src/cache/docWritethrough.d.ts +21 -0
- package/dist/src/cache/docWritethrough.js +107 -0
- package/dist/src/cache/docWritethrough.js.map +1 -0
- package/dist/src/cache/generic.d.ts +2 -2
- package/dist/src/cache/generic.js.map +1 -1
- package/dist/src/cache/index.d.ts +1 -0
- package/dist/src/cache/index.js +2 -1
- package/dist/src/cache/index.js.map +1 -1
- package/dist/src/configs/configs.d.ts +1 -1
- package/dist/src/constants/db.d.ts +3 -0
- package/dist/src/constants/db.js +3 -0
- package/dist/src/constants/db.js.map +1 -1
- package/dist/src/context/mainContext.d.ts +1 -0
- package/dist/src/context/mainContext.js +13 -1
- package/dist/src/context/mainContext.js.map +1 -1
- package/dist/src/db/couch/DatabaseImpl.d.ts +3 -1
- package/dist/src/db/couch/DatabaseImpl.js +18 -1
- package/dist/src/db/couch/DatabaseImpl.js.map +1 -1
- package/dist/src/db/instrumentation.d.ts +1 -1
- package/dist/src/db/instrumentation.js +5 -2
- package/dist/src/db/instrumentation.js.map +1 -1
- package/dist/src/environment.d.ts +1 -0
- package/dist/src/environment.js +1 -1
- package/dist/src/environment.js.map +1 -1
- package/dist/src/events/analytics.d.ts +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/queue/constants.d.ts +2 -1
- package/dist/src/queue/constants.js +1 -0
- package/dist/src/queue/constants.js.map +1 -1
- package/dist/src/queue/inMemoryQueue.d.ts +23 -13
- package/dist/src/queue/inMemoryQueue.js +83 -30
- package/dist/src/queue/inMemoryQueue.js.map +1 -1
- package/dist/src/queue/listeners.js +2 -0
- package/dist/src/queue/listeners.js.map +1 -1
- package/dist/src/queue/queue.d.ts +1 -0
- package/dist/src/queue/queue.js.map +1 -1
- package/dist/src/redis/init.d.ts +1 -0
- package/dist/src/redis/init.js +12 -2
- package/dist/src/redis/init.js.map +1 -1
- package/dist/src/redis/redis.d.ts +1 -0
- package/dist/src/redis/redis.js +6 -0
- package/dist/src/redis/redis.js.map +1 -1
- package/dist/src/redis/utils.d.ts +2 -1
- package/dist/src/redis/utils.js +1 -0
- package/dist/src/redis/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/cache/base/index.ts +62 -4
- package/src/cache/docWritethrough.ts +97 -0
- package/src/cache/generic.ts +3 -2
- package/src/cache/index.ts +1 -0
- package/src/cache/tests/docWritethrough.spec.ts +293 -0
- package/src/constants/db.ts +3 -0
- package/src/context/mainContext.ts +11 -0
- package/src/db/couch/DatabaseImpl.ts +18 -1
- package/src/db/instrumentation.ts +5 -2
- package/src/db/tests/DatabaseImpl.spec.ts +55 -0
- package/src/environment.ts +1 -0
- package/src/queue/constants.ts +1 -0
- package/src/queue/inMemoryQueue.ts +79 -24
- package/src/queue/listeners.ts +2 -0
- package/src/queue/queue.ts +2 -0
- package/src/redis/init.ts +12 -1
- package/src/redis/redis.ts +5 -0
- package/src/redis/utils.ts +1 -0
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import events from "events"
|
|
2
|
-
import { timeout } from "../utils"
|
|
2
|
+
import { newid, timeout } from "../utils"
|
|
3
|
+
import { Queue, QueueOptions, JobOptions } from "./queue"
|
|
4
|
+
|
|
5
|
+
interface JobMessage {
|
|
6
|
+
id: string
|
|
7
|
+
timestamp: number
|
|
8
|
+
queue: string
|
|
9
|
+
data: any
|
|
10
|
+
opts?: JobOptions
|
|
11
|
+
}
|
|
3
12
|
|
|
4
13
|
/**
|
|
5
14
|
* Bull works with a Job wrapper around all messages that contains a lot more information about
|
|
@@ -10,12 +19,13 @@ import { timeout } from "../utils"
|
|
|
10
19
|
* @returns A new job which can now be put onto the queue, this is mostly an
|
|
11
20
|
* internal structure so that an in memory queue can be easily swapped for a Bull queue.
|
|
12
21
|
*/
|
|
13
|
-
function newJob(queue: string, message: any) {
|
|
22
|
+
function newJob(queue: string, message: any, opts?: JobOptions): JobMessage {
|
|
14
23
|
return {
|
|
24
|
+
id: newid(),
|
|
15
25
|
timestamp: Date.now(),
|
|
16
26
|
queue: queue,
|
|
17
27
|
data: message,
|
|
18
|
-
opts
|
|
28
|
+
opts,
|
|
19
29
|
}
|
|
20
30
|
}
|
|
21
31
|
|
|
@@ -24,26 +34,29 @@ function newJob(queue: string, message: any) {
|
|
|
24
34
|
* It is relatively simple, using an event emitter internally to register when messages are available
|
|
25
35
|
* to the consumers - in can support many inputs and many consumers.
|
|
26
36
|
*/
|
|
27
|
-
class InMemoryQueue {
|
|
37
|
+
class InMemoryQueue implements Partial<Queue> {
|
|
28
38
|
_name: string
|
|
29
|
-
_opts?:
|
|
30
|
-
_messages:
|
|
39
|
+
_opts?: QueueOptions
|
|
40
|
+
_messages: JobMessage[]
|
|
41
|
+
_queuedJobIds: Set<string>
|
|
31
42
|
_emitter: EventEmitter
|
|
32
43
|
_runCount: number
|
|
33
44
|
_addCount: number
|
|
45
|
+
|
|
34
46
|
/**
|
|
35
47
|
* The constructor the queue, exactly the same as that of Bulls.
|
|
36
48
|
* @param name The name of the queue which is being configured.
|
|
37
49
|
* @param opts This is not used by the in memory queue as there is no real use
|
|
38
50
|
* case when in memory, but is the same API as Bull
|
|
39
51
|
*/
|
|
40
|
-
constructor(name: string, opts?:
|
|
52
|
+
constructor(name: string, opts?: QueueOptions) {
|
|
41
53
|
this._name = name
|
|
42
54
|
this._opts = opts
|
|
43
55
|
this._messages = []
|
|
44
56
|
this._emitter = new events.EventEmitter()
|
|
45
57
|
this._runCount = 0
|
|
46
58
|
this._addCount = 0
|
|
59
|
+
this._queuedJobIds = new Set<string>()
|
|
47
60
|
}
|
|
48
61
|
|
|
49
62
|
/**
|
|
@@ -55,22 +68,42 @@ class InMemoryQueue {
|
|
|
55
68
|
* note this is incredibly limited compared to Bull as in reality the Job would contain
|
|
56
69
|
* a lot more information about the queue and current status of Bull cluster.
|
|
57
70
|
*/
|
|
58
|
-
process(func: any) {
|
|
71
|
+
async process(func: any) {
|
|
59
72
|
this._emitter.on("message", async () => {
|
|
60
73
|
if (this._messages.length <= 0) {
|
|
61
74
|
return
|
|
62
75
|
}
|
|
63
76
|
let msg = this._messages.shift()
|
|
77
|
+
|
|
64
78
|
let resp = func(msg)
|
|
79
|
+
|
|
80
|
+
async function retryFunc(fnc: any) {
|
|
81
|
+
try {
|
|
82
|
+
await fnc
|
|
83
|
+
} catch (e: any) {
|
|
84
|
+
await new Promise<void>(r => setTimeout(() => r(), 50))
|
|
85
|
+
|
|
86
|
+
await retryFunc(func(msg))
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
65
90
|
if (resp.then != null) {
|
|
66
|
-
|
|
91
|
+
try {
|
|
92
|
+
await retryFunc(resp)
|
|
93
|
+
} catch (e: any) {
|
|
94
|
+
console.error(e)
|
|
95
|
+
}
|
|
67
96
|
}
|
|
68
97
|
this._runCount++
|
|
98
|
+
const jobId = msg?.opts?.jobId?.toString()
|
|
99
|
+
if (jobId && msg?.opts?.removeOnComplete) {
|
|
100
|
+
this._queuedJobIds.delete(jobId)
|
|
101
|
+
}
|
|
69
102
|
})
|
|
70
103
|
}
|
|
71
104
|
|
|
72
105
|
async isReady() {
|
|
73
|
-
return
|
|
106
|
+
return this as any
|
|
74
107
|
}
|
|
75
108
|
|
|
76
109
|
// simply puts a message to the queue and emits to the queue for processing
|
|
@@ -83,27 +116,45 @@ class InMemoryQueue {
|
|
|
83
116
|
* @param repeat serves no purpose for the import queue.
|
|
84
117
|
*/
|
|
85
118
|
// eslint-disable-next-line no-unused-vars
|
|
86
|
-
add(
|
|
87
|
-
|
|
119
|
+
async add(data: any, opts?: JobOptions) {
|
|
120
|
+
const jobId = opts?.jobId?.toString()
|
|
121
|
+
if (jobId && this._queuedJobIds.has(jobId)) {
|
|
122
|
+
console.log(`Ignoring already queued job ${jobId}`)
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (typeof data !== "object") {
|
|
88
127
|
throw "Queue only supports carrying JSON."
|
|
89
128
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
129
|
+
if (jobId) {
|
|
130
|
+
this._queuedJobIds.add(jobId)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const pushMessage = () => {
|
|
134
|
+
this._messages.push(newJob(this._name, data, opts))
|
|
135
|
+
this._addCount++
|
|
136
|
+
this._emitter.emit("message")
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const delay = opts?.delay
|
|
140
|
+
if (delay) {
|
|
141
|
+
setTimeout(pushMessage, delay)
|
|
142
|
+
} else {
|
|
143
|
+
pushMessage()
|
|
144
|
+
}
|
|
145
|
+
return {} as any
|
|
93
146
|
}
|
|
94
147
|
|
|
95
148
|
/**
|
|
96
149
|
* replicating the close function from bull, which waits for jobs to finish.
|
|
97
150
|
*/
|
|
98
|
-
async close() {
|
|
99
|
-
return []
|
|
100
|
-
}
|
|
151
|
+
async close() {}
|
|
101
152
|
|
|
102
153
|
/**
|
|
103
154
|
* This removes a cron which has been implemented, this is part of Bull API.
|
|
104
155
|
* @param cronJobId The cron which is to be removed.
|
|
105
156
|
*/
|
|
106
|
-
removeRepeatableByKey(cronJobId: string) {
|
|
157
|
+
async removeRepeatableByKey(cronJobId: string) {
|
|
107
158
|
// TODO: implement for testing
|
|
108
159
|
console.log(cronJobId)
|
|
109
160
|
}
|
|
@@ -111,12 +162,12 @@ class InMemoryQueue {
|
|
|
111
162
|
/**
|
|
112
163
|
* Implemented for tests
|
|
113
164
|
*/
|
|
114
|
-
getRepeatableJobs() {
|
|
165
|
+
async getRepeatableJobs() {
|
|
115
166
|
return []
|
|
116
167
|
}
|
|
117
168
|
|
|
118
169
|
// eslint-disable-next-line no-unused-vars
|
|
119
|
-
removeJobs(pattern: string) {
|
|
170
|
+
async removeJobs(pattern: string) {
|
|
120
171
|
// no-op
|
|
121
172
|
}
|
|
122
173
|
|
|
@@ -128,18 +179,22 @@ class InMemoryQueue {
|
|
|
128
179
|
}
|
|
129
180
|
|
|
130
181
|
async getJob() {
|
|
131
|
-
return
|
|
182
|
+
return null
|
|
132
183
|
}
|
|
133
184
|
|
|
134
185
|
on() {
|
|
135
186
|
// do nothing
|
|
136
|
-
return this
|
|
187
|
+
return this as any
|
|
137
188
|
}
|
|
138
189
|
|
|
139
190
|
async waitForCompletion() {
|
|
140
191
|
do {
|
|
141
192
|
await timeout(50)
|
|
142
|
-
} while (this.
|
|
193
|
+
} while (this.hasRunningJobs())
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
hasRunningJobs() {
|
|
197
|
+
return this._addCount > this._runCount
|
|
143
198
|
}
|
|
144
199
|
}
|
|
145
200
|
|
package/src/queue/listeners.ts
CHANGED
|
@@ -88,6 +88,7 @@ enum QueueEventType {
|
|
|
88
88
|
AUDIT_LOG_EVENT = "audit-log-event",
|
|
89
89
|
SYSTEM_EVENT = "system-event",
|
|
90
90
|
APP_MIGRATION = "app-migration",
|
|
91
|
+
DOC_WRITETHROUGH = "doc-writethrough",
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
const EventTypeMap: { [key in JobQueue]: QueueEventType } = {
|
|
@@ -96,6 +97,7 @@ const EventTypeMap: { [key in JobQueue]: QueueEventType } = {
|
|
|
96
97
|
[JobQueue.AUDIT_LOG]: QueueEventType.AUDIT_LOG_EVENT,
|
|
97
98
|
[JobQueue.SYSTEM_EVENT_QUEUE]: QueueEventType.SYSTEM_EVENT,
|
|
98
99
|
[JobQueue.APP_MIGRATION]: QueueEventType.APP_MIGRATION,
|
|
100
|
+
[JobQueue.DOC_WRITETHROUGH_QUEUE]: QueueEventType.DOC_WRITETHROUGH,
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
function logging(queue: Queue, jobQueue: JobQueue) {
|
package/src/queue/queue.ts
CHANGED
|
@@ -7,6 +7,8 @@ import { addListeners, StalledFn } from "./listeners"
|
|
|
7
7
|
import { Duration } from "../utils"
|
|
8
8
|
import * as timers from "../timers"
|
|
9
9
|
|
|
10
|
+
export { QueueOptions, Queue, JobOptions } from "bull"
|
|
11
|
+
|
|
10
12
|
// the queue lock is held for 5 minutes
|
|
11
13
|
const QUEUE_LOCK_MS = Duration.fromMinutes(5).toMs()
|
|
12
14
|
// queue lock is refreshed every 30 seconds
|
package/src/redis/init.ts
CHANGED
|
@@ -9,7 +9,8 @@ let userClient: Client,
|
|
|
9
9
|
lockClient: Client,
|
|
10
10
|
socketClient: Client,
|
|
11
11
|
inviteClient: Client,
|
|
12
|
-
passwordResetClient: Client
|
|
12
|
+
passwordResetClient: Client,
|
|
13
|
+
docWritethroughClient: Client
|
|
13
14
|
|
|
14
15
|
export async function init() {
|
|
15
16
|
userClient = await new Client(utils.Databases.USER_CACHE).init()
|
|
@@ -24,6 +25,9 @@ export async function init() {
|
|
|
24
25
|
utils.Databases.SOCKET_IO,
|
|
25
26
|
utils.SelectableDatabase.SOCKET_IO
|
|
26
27
|
).init()
|
|
28
|
+
docWritethroughClient = await new Client(
|
|
29
|
+
utils.Databases.DOC_WRITE_THROUGH
|
|
30
|
+
).init()
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
export async function shutdown() {
|
|
@@ -104,3 +108,10 @@ export async function getPasswordResetClient() {
|
|
|
104
108
|
}
|
|
105
109
|
return passwordResetClient
|
|
106
110
|
}
|
|
111
|
+
|
|
112
|
+
export async function getDocWritethroughClient() {
|
|
113
|
+
if (!writethroughClient) {
|
|
114
|
+
await init()
|
|
115
|
+
}
|
|
116
|
+
return writethroughClient
|
|
117
|
+
}
|
package/src/redis/redis.ts
CHANGED
|
@@ -320,6 +320,11 @@ class RedisWrapper {
|
|
|
320
320
|
await this.getClient().del(addDbPrefix(db, key))
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
async bulkDelete(keys: string[]) {
|
|
324
|
+
const db = this._db
|
|
325
|
+
await this.getClient().del(keys.map(key => addDbPrefix(db, key)))
|
|
326
|
+
}
|
|
327
|
+
|
|
323
328
|
async clear() {
|
|
324
329
|
let items = await this.scan()
|
|
325
330
|
await Promise.all(items.map((obj: any) => this.delete(obj.key)))
|