fauxqs 2.4.1 → 2.4.2
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/README.md +129 -0
- package/dist/app.d.ts +15 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +75 -6
- package/dist/app.js.map +1 -1
- package/dist/s3/s3Store.d.ts +1 -1
- package/dist/s3/s3Store.d.ts.map +1 -1
- package/dist/s3/s3Store.js +3 -0
- package/dist/s3/s3Store.js.map +1 -1
- package/dist/server.js +60 -0
- package/dist/server.js.map +1 -1
- package/dist/sns/snsStore.d.ts +1 -0
- package/dist/sns/snsStore.d.ts.map +1 -1
- package/dist/sns/snsStore.js +6 -0
- package/dist/sns/snsStore.js.map +1 -1
- package/dist/sqs/sqsStore.d.ts.map +1 -1
- package/dist/sqs/sqsStore.js +3 -0
- package/dist/sqs/sqsStore.js.map +1 -1
- package/dist/tenant/tenantManager.d.ts +79 -0
- package/dist/tenant/tenantManager.d.ts.map +1 -0
- package/dist/tenant/tenantManager.js +533 -0
- package/dist/tenant/tenantManager.js.map +1 -0
- package/dist/tenant/tenantTypes.d.ts +26 -0
- package/dist/tenant/tenantTypes.d.ts.map +1 -0
- package/dist/tenant/tenantTypes.js +6 -0
- package/dist/tenant/tenantTypes.js.map +1 -0
- package/dist/tenant/trackedStores.d.ts +93 -0
- package/dist/tenant/trackedStores.d.ts.map +1 -0
- package/dist/tenant/trackedStores.js +122 -0
- package/dist/tenant/trackedStores.js.map +1 -0
- package/dist/tenant/usageTracker.d.ts +40 -0
- package/dist/tenant/usageTracker.d.ts.map +1 -0
- package/dist/tenant/usageTracker.js +87 -0
- package/dist/tenant/usageTracker.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import { sqsQueueArn, snsTopicArn } from "../common/arnHelper.js";
|
|
2
|
+
import { applyInitConfig } from "../initConfig.js";
|
|
3
|
+
import { defaultTenantLogger } from "./tenantTypes.js";
|
|
4
|
+
const DEFAULT_ADMIN_QUEUE_NAME = "_fauxqs-admin";
|
|
5
|
+
const DEFAULT_SWEEP_BUDGET = 50;
|
|
6
|
+
const ADMIN_POLL_INTERVAL_MS = 500;
|
|
7
|
+
const MIN_SWEEP_INTERVAL_MS = 50;
|
|
8
|
+
export class TenantManager {
|
|
9
|
+
usageTracker;
|
|
10
|
+
config;
|
|
11
|
+
sqsStore;
|
|
12
|
+
snsStore;
|
|
13
|
+
s3Store;
|
|
14
|
+
region;
|
|
15
|
+
port;
|
|
16
|
+
template;
|
|
17
|
+
permanentPrefixes;
|
|
18
|
+
sweepBudget;
|
|
19
|
+
adminQueueName;
|
|
20
|
+
logger;
|
|
21
|
+
instantiatedPrefixes = new Set();
|
|
22
|
+
sweepCursor;
|
|
23
|
+
pendingExpired = new Map();
|
|
24
|
+
sweepTimer;
|
|
25
|
+
sweepIntervalMs = 0;
|
|
26
|
+
sweepRunning = false;
|
|
27
|
+
adminPollTimer;
|
|
28
|
+
constructor(config, sqsStore, snsStore, s3Store, usageTracker, context, template, logger) {
|
|
29
|
+
this.config = config;
|
|
30
|
+
this.sqsStore = sqsStore;
|
|
31
|
+
this.snsStore = snsStore;
|
|
32
|
+
this.s3Store = s3Store;
|
|
33
|
+
this.usageTracker = usageTracker;
|
|
34
|
+
this.region = context.region;
|
|
35
|
+
this.port = context.port;
|
|
36
|
+
this.logger = logger ?? defaultTenantLogger;
|
|
37
|
+
this.template = config.template ?? template;
|
|
38
|
+
this.permanentPrefixes = new Set(config.permanentPrefixes ?? []);
|
|
39
|
+
const budget = config.sweepBudget ?? DEFAULT_SWEEP_BUDGET;
|
|
40
|
+
if (budget <= 0) {
|
|
41
|
+
throw new Error(`sweepBudget must be a positive integer (got ${budget})`);
|
|
42
|
+
}
|
|
43
|
+
this.sweepBudget = budget;
|
|
44
|
+
// Resolve admin queue name
|
|
45
|
+
if (config.adminQueue === true) {
|
|
46
|
+
this.adminQueueName = DEFAULT_ADMIN_QUEUE_NAME;
|
|
47
|
+
}
|
|
48
|
+
else if (typeof config.adminQueue === "string") {
|
|
49
|
+
this.adminQueueName = config.adminQueue;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Update the port after the server starts listening. Must be called before start(). */
|
|
53
|
+
setPort(port) {
|
|
54
|
+
this.port = port;
|
|
55
|
+
}
|
|
56
|
+
/** Start sweep timer and admin queue polling (if enabled). */
|
|
57
|
+
start() {
|
|
58
|
+
// Seed the usage tracker from existing store state so that resources loaded
|
|
59
|
+
// from persistence (or created via init config before start()) begin with a
|
|
60
|
+
// fresh "just used" timestamp instead of being absent from the tracker and
|
|
61
|
+
// therefore invisible to the sweep.
|
|
62
|
+
this.seedFromStores();
|
|
63
|
+
// Start sweep timer — uses setTimeout chain instead of setInterval so the next
|
|
64
|
+
// tick only starts after the previous one finishes (backpressure).
|
|
65
|
+
this.sweepIntervalMs = Math.max(this.config.sweepIntervalMs ?? Math.floor(this.config.ttlMs / 10), MIN_SWEEP_INTERVAL_MS);
|
|
66
|
+
this.sweepRunning = true;
|
|
67
|
+
this.scheduleSweep();
|
|
68
|
+
// Create and start polling the admin queue if enabled
|
|
69
|
+
if (this.adminQueueName) {
|
|
70
|
+
this.createAdminQueue();
|
|
71
|
+
this.adminPollTimer = setInterval(() => this.pollAdminQueue(), ADMIN_POLL_INTERVAL_MS);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Reset all tenant state (called on purgeAll). */
|
|
75
|
+
reset() {
|
|
76
|
+
this.usageTracker.clear();
|
|
77
|
+
this.instantiatedPrefixes.clear();
|
|
78
|
+
this.pendingExpired.clear();
|
|
79
|
+
this.sweepCursor = undefined;
|
|
80
|
+
// Recreate admin queue if it was enabled (purgeAll wipes all queues)
|
|
81
|
+
if (this.adminQueueName) {
|
|
82
|
+
this.createAdminQueue();
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/** Stop all timers. */
|
|
86
|
+
shutdown() {
|
|
87
|
+
this.sweepRunning = false;
|
|
88
|
+
if (this.sweepTimer) {
|
|
89
|
+
clearTimeout(this.sweepTimer);
|
|
90
|
+
this.sweepTimer = undefined;
|
|
91
|
+
}
|
|
92
|
+
if (this.adminPollTimer) {
|
|
93
|
+
clearInterval(this.adminPollTimer);
|
|
94
|
+
this.adminPollTimer = undefined;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Instantiate the template with a given prefix. Idempotent. */
|
|
98
|
+
instantiateTemplate(prefix) {
|
|
99
|
+
if (!this.template) {
|
|
100
|
+
throw new Error("No template configured for tenant instantiation");
|
|
101
|
+
}
|
|
102
|
+
// If prefix already exists, just bump usage timestamps
|
|
103
|
+
if (this.instantiatedPrefixes.has(prefix)) {
|
|
104
|
+
this.touchAllInPrefix(prefix);
|
|
105
|
+
return { queues: [], topics: [], subscriptions: [], buckets: [] };
|
|
106
|
+
}
|
|
107
|
+
const prefixedConfig = this.prefixConfig(this.template, prefix);
|
|
108
|
+
const result = applyInitConfig(prefixedConfig, this.sqsStore, this.snsStore, this.s3Store, {
|
|
109
|
+
port: this.port,
|
|
110
|
+
region: this.region,
|
|
111
|
+
});
|
|
112
|
+
// Register all created resources with explicit prefix in the usage tracker
|
|
113
|
+
this.registerTemplateResources(prefix);
|
|
114
|
+
this.instantiatedPrefixes.add(prefix);
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
/** List all instantiated prefixes with their oldest last-used timestamp. */
|
|
118
|
+
listTenants() {
|
|
119
|
+
const result = [];
|
|
120
|
+
for (const prefix of this.instantiatedPrefixes) {
|
|
121
|
+
let oldestMs = Date.now();
|
|
122
|
+
const names = this.getResourceNamesForPrefix(prefix);
|
|
123
|
+
for (const name of names) {
|
|
124
|
+
const entry = this.usageTracker.get(name);
|
|
125
|
+
if (entry && entry.lastUsedMs < oldestMs) {
|
|
126
|
+
oldestMs = entry.lastUsedMs;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
result.push({ prefix, lastUsedMs: oldestMs });
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
/** Force-delete all resources for a given prefix. */
|
|
134
|
+
deleteTenant(prefix) {
|
|
135
|
+
if (!this.instantiatedPrefixes.has(prefix))
|
|
136
|
+
return;
|
|
137
|
+
this.deleteResourceSet(prefix);
|
|
138
|
+
this.instantiatedPrefixes.delete(prefix);
|
|
139
|
+
this.pendingExpired.delete(prefix);
|
|
140
|
+
}
|
|
141
|
+
// --- Private: Sweep ---
|
|
142
|
+
scheduleSweep() {
|
|
143
|
+
if (!this.sweepRunning)
|
|
144
|
+
return;
|
|
145
|
+
this.sweepTimer = setTimeout(() => {
|
|
146
|
+
this.sweepTick();
|
|
147
|
+
this.scheduleSweep();
|
|
148
|
+
}, this.sweepIntervalMs);
|
|
149
|
+
}
|
|
150
|
+
sweepTick() {
|
|
151
|
+
const cutoff = Date.now() - this.config.ttlMs;
|
|
152
|
+
const { visited, nextCursor, wrapped } = this.usageTracker.scan(this.sweepCursor, this.sweepBudget);
|
|
153
|
+
this.sweepCursor = nextCursor;
|
|
154
|
+
for (const [name, entry] of visited) {
|
|
155
|
+
if (entry.lastUsedMs >= cutoff) {
|
|
156
|
+
// Not expired — remove from pending if it was there
|
|
157
|
+
this.removePendingEntry(entry.prefix, name);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
// Check permanent status
|
|
161
|
+
if (this.isResourcePermanent(name, entry.prefix))
|
|
162
|
+
continue;
|
|
163
|
+
// Add to pending expired
|
|
164
|
+
let pending = this.pendingExpired.get(entry.prefix);
|
|
165
|
+
if (!pending) {
|
|
166
|
+
pending = new Set();
|
|
167
|
+
this.pendingExpired.set(entry.prefix, pending);
|
|
168
|
+
}
|
|
169
|
+
pending.add(name);
|
|
170
|
+
}
|
|
171
|
+
// Only process deletions after a full cycle (wrapped around)
|
|
172
|
+
if (wrapped) {
|
|
173
|
+
this.processPendingDeletions();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
processPendingDeletions() {
|
|
177
|
+
const cutoff = Date.now() - this.config.ttlMs;
|
|
178
|
+
const toDelete = [];
|
|
179
|
+
const deletedNames = new Set();
|
|
180
|
+
for (const [prefix, pendingNames] of this.pendingExpired) {
|
|
181
|
+
// Re-verify: remove any resources that were touched since being marked pending
|
|
182
|
+
for (const name of pendingNames) {
|
|
183
|
+
const entry = this.usageTracker.get(name);
|
|
184
|
+
if (!entry || entry.lastUsedMs >= cutoff) {
|
|
185
|
+
pendingNames.delete(name);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (pendingNames.size === 0) {
|
|
189
|
+
toDelete.push(prefix);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (prefix === null) {
|
|
193
|
+
for (const name of pendingNames)
|
|
194
|
+
deletedNames.add(name);
|
|
195
|
+
toDelete.push(prefix);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const expectedNames = this.getResourceNamesForPrefix(prefix);
|
|
199
|
+
const allExpired = expectedNames.every((n) => pendingNames.has(n));
|
|
200
|
+
if (allExpired) {
|
|
201
|
+
for (const name of pendingNames)
|
|
202
|
+
deletedNames.add(name);
|
|
203
|
+
toDelete.push(prefix);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Advance cursor past any about-to-be-deleted entry BEFORE performing
|
|
207
|
+
// deletions — the entries still exist in the tracker at this point.
|
|
208
|
+
if (this.sweepCursor && deletedNames.has(this.sweepCursor)) {
|
|
209
|
+
this.sweepCursor = this.usageTracker.nextAfter(this.sweepCursor);
|
|
210
|
+
}
|
|
211
|
+
// Now perform the actual deletions
|
|
212
|
+
for (const [prefix, pendingNames] of this.pendingExpired) {
|
|
213
|
+
if (!toDelete.includes(prefix))
|
|
214
|
+
continue;
|
|
215
|
+
if (prefix === null) {
|
|
216
|
+
for (const name of pendingNames) {
|
|
217
|
+
this.deleteIndividualResource(name);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this.deleteResourceSet(prefix);
|
|
222
|
+
this.instantiatedPrefixes.delete(prefix);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
for (const prefix of toDelete) {
|
|
226
|
+
this.pendingExpired.delete(prefix);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
isResourcePermanent(name, prefix) {
|
|
230
|
+
// Admin queue is always permanent
|
|
231
|
+
if (this.adminQueueName && name === this.adminQueueName)
|
|
232
|
+
return true;
|
|
233
|
+
if (prefix === null) {
|
|
234
|
+
return this.permanentPrefixes.has("");
|
|
235
|
+
}
|
|
236
|
+
return this.permanentPrefixes.has(prefix);
|
|
237
|
+
}
|
|
238
|
+
removePendingEntry(prefix, name) {
|
|
239
|
+
const pending = this.pendingExpired.get(prefix);
|
|
240
|
+
if (pending) {
|
|
241
|
+
pending.delete(name);
|
|
242
|
+
if (pending.size === 0) {
|
|
243
|
+
this.pendingExpired.delete(prefix);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// --- Private: Resource deletion ---
|
|
248
|
+
deleteResourceSet(prefix) {
|
|
249
|
+
if (!this.template)
|
|
250
|
+
return;
|
|
251
|
+
// 1. Remove subscriptions first
|
|
252
|
+
if (this.template.subscriptions) {
|
|
253
|
+
for (const sub of this.template.subscriptions) {
|
|
254
|
+
const topicArn = snsTopicArn(prefix + sub.topic, this.region);
|
|
255
|
+
const queueArn = sqsQueueArn(prefix + sub.queue, this.region);
|
|
256
|
+
this.removeSubscription(topicArn, queueArn);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// 2. Delete topics
|
|
260
|
+
if (this.template.topics) {
|
|
261
|
+
for (const t of this.template.topics) {
|
|
262
|
+
const fullName = prefix + t.name;
|
|
263
|
+
const arn = snsTopicArn(fullName, this.region);
|
|
264
|
+
try {
|
|
265
|
+
this.snsStore.deleteTopic(arn);
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
// Topic may already be deleted
|
|
269
|
+
}
|
|
270
|
+
this.usageTracker.delete(fullName);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// 3. Delete queues
|
|
274
|
+
if (this.template.queues) {
|
|
275
|
+
for (const q of this.template.queues) {
|
|
276
|
+
const fullName = prefix + q.name;
|
|
277
|
+
try {
|
|
278
|
+
const queue = this.sqsStore.getQueueByName(fullName);
|
|
279
|
+
if (queue) {
|
|
280
|
+
queue.cancelWaiters();
|
|
281
|
+
this.sqsStore.deleteQueue(queue.url);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch {
|
|
285
|
+
// Queue may already be deleted
|
|
286
|
+
}
|
|
287
|
+
this.usageTracker.delete(fullName);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// 4. Empty and delete buckets
|
|
291
|
+
if (this.template.buckets) {
|
|
292
|
+
for (const entry of this.template.buckets) {
|
|
293
|
+
const baseName = typeof entry === "string" ? entry : entry.name;
|
|
294
|
+
const fullName = prefix + baseName;
|
|
295
|
+
this.s3Store.emptyBucket(fullName);
|
|
296
|
+
try {
|
|
297
|
+
this.s3Store.deleteBucket(fullName);
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
// Bucket may not exist or may have concurrent uploads — skip, retry next cycle
|
|
301
|
+
}
|
|
302
|
+
this.usageTracker.delete(fullName);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
deleteIndividualResource(name) {
|
|
307
|
+
// Try to find and delete the resource by name across all stores.
|
|
308
|
+
// Queue and bucket lookups are O(1). Topic uses ARN construction
|
|
309
|
+
// with the known region to avoid O(n) scan over all topics.
|
|
310
|
+
const queue = this.sqsStore.getQueueByName(name);
|
|
311
|
+
if (queue) {
|
|
312
|
+
queue.cancelWaiters();
|
|
313
|
+
this.sqsStore.deleteQueue(queue.url);
|
|
314
|
+
this.usageTracker.delete(name);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const topicArn = snsTopicArn(name, this.region);
|
|
318
|
+
if (this.snsStore.getTopic(topicArn)) {
|
|
319
|
+
this.snsStore.deleteTopic(topicArn);
|
|
320
|
+
this.usageTracker.delete(name);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (this.s3Store.hasBucket(name)) {
|
|
324
|
+
this.s3Store.emptyBucket(name);
|
|
325
|
+
try {
|
|
326
|
+
this.s3Store.deleteBucket(name);
|
|
327
|
+
}
|
|
328
|
+
catch {
|
|
329
|
+
// Skip on error
|
|
330
|
+
}
|
|
331
|
+
this.usageTracker.delete(name);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
removeSubscription(topicArn, queueArn) {
|
|
335
|
+
// Find and remove all subscriptions matching this topic+queue pair.
|
|
336
|
+
// Collect ARNs first to avoid mutating the map during iteration.
|
|
337
|
+
const toRemove = [];
|
|
338
|
+
for (const [subArn, sub] of this.snsStore.subscriptions) {
|
|
339
|
+
if (sub.topicArn === topicArn && sub.endpoint === queueArn) {
|
|
340
|
+
toRemove.push(subArn);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
for (const subArn of toRemove) {
|
|
344
|
+
this.snsStore.unsubscribe(subArn);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
// --- Private: Template helpers ---
|
|
348
|
+
prefixConfig(config, prefix) {
|
|
349
|
+
return {
|
|
350
|
+
region: config.region,
|
|
351
|
+
queues: config.queues?.map((q) => ({
|
|
352
|
+
...q,
|
|
353
|
+
name: prefix + q.name,
|
|
354
|
+
attributes: q.attributes ? this.prefixQueueAttributes(q.attributes, prefix) : undefined,
|
|
355
|
+
})),
|
|
356
|
+
topics: config.topics?.map((t) => ({ ...t, name: prefix + t.name })),
|
|
357
|
+
subscriptions: config.subscriptions?.map((s) => ({
|
|
358
|
+
...s,
|
|
359
|
+
topic: prefix + s.topic,
|
|
360
|
+
queue: prefix + s.queue,
|
|
361
|
+
})),
|
|
362
|
+
buckets: config.buckets?.map((b) => typeof b === "string" ? prefix + b : { ...b, name: prefix + b.name }),
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
/** Rewrite ARNs inside RedrivePolicy so DLQ references point to the prefixed queue. */
|
|
366
|
+
prefixQueueAttributes(attrs, prefix) {
|
|
367
|
+
if (!attrs.RedrivePolicy)
|
|
368
|
+
return attrs;
|
|
369
|
+
try {
|
|
370
|
+
const policy = JSON.parse(attrs.RedrivePolicy);
|
|
371
|
+
if (typeof policy.deadLetterTargetArn === "string") {
|
|
372
|
+
// ARN format: arn:aws:sqs:region:account:queueName — prefix the queue name portion
|
|
373
|
+
const parts = policy.deadLetterTargetArn.split(":");
|
|
374
|
+
if (parts.length === 6) {
|
|
375
|
+
parts[5] = prefix + parts[5];
|
|
376
|
+
policy.deadLetterTargetArn = parts.join(":");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return { ...attrs, RedrivePolicy: JSON.stringify(policy) };
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
throw new Error(`Failed to prefix RedrivePolicy for tenant: ${err instanceof Error ? err.message : err}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Seed the usage tracker from current store contents. Infers tenant prefixes
|
|
387
|
+
* from template resource names so that resources loaded from persistence start
|
|
388
|
+
* with a "just used" timestamp rather than being absent (and thus invisible to
|
|
389
|
+
* the sweep until they are accessed).
|
|
390
|
+
*/
|
|
391
|
+
seedFromStores() {
|
|
392
|
+
// Collect all template base names for prefix inference
|
|
393
|
+
const templateQueueNames = new Set(this.template?.queues?.map((q) => q.name) ?? []);
|
|
394
|
+
const templateTopicNames = new Set(this.template?.topics?.map((t) => t.name) ?? []);
|
|
395
|
+
const templateBucketNames = new Set(this.template?.buckets?.map((b) => (typeof b === "string" ? b : b.name)) ?? []);
|
|
396
|
+
// Scan queues
|
|
397
|
+
for (const queue of this.sqsStore.allQueues()) {
|
|
398
|
+
if (this.usageTracker.get(queue.name))
|
|
399
|
+
continue; // already registered
|
|
400
|
+
const prefix = this.inferPrefix(queue.name, templateQueueNames);
|
|
401
|
+
if (prefix !== undefined) {
|
|
402
|
+
this.usageTracker.register(queue.name, prefix);
|
|
403
|
+
if (prefix !== null)
|
|
404
|
+
this.instantiatedPrefixes.add(prefix);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
// Non-template resource — register with null prefix
|
|
408
|
+
this.usageTracker.register(queue.name, null);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
// Scan topics
|
|
412
|
+
for (const topic of this.snsStore.allTopics()) {
|
|
413
|
+
if (this.usageTracker.get(topic.name))
|
|
414
|
+
continue;
|
|
415
|
+
const prefix = this.inferPrefix(topic.name, templateTopicNames);
|
|
416
|
+
if (prefix !== undefined) {
|
|
417
|
+
this.usageTracker.register(topic.name, prefix);
|
|
418
|
+
if (prefix !== null)
|
|
419
|
+
this.instantiatedPrefixes.add(prefix);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
this.usageTracker.register(topic.name, null);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// Scan buckets
|
|
426
|
+
for (const { name } of this.s3Store.listBuckets()) {
|
|
427
|
+
if (this.usageTracker.get(name))
|
|
428
|
+
continue;
|
|
429
|
+
const prefix = this.inferPrefix(name, templateBucketNames);
|
|
430
|
+
if (prefix !== undefined) {
|
|
431
|
+
this.usageTracker.register(name, prefix);
|
|
432
|
+
if (prefix !== null)
|
|
433
|
+
this.instantiatedPrefixes.add(prefix);
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
this.usageTracker.register(name, null);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Given a resource name and a set of template base names, return the prefix
|
|
442
|
+
* if the name matches (e.g. "tenant1-orders" with base "orders" → "tenant1-"),
|
|
443
|
+
* or null if the name exactly matches a base name (no prefix), or undefined
|
|
444
|
+
* if the name doesn't match any template base name.
|
|
445
|
+
*/
|
|
446
|
+
inferPrefix(name, templateBaseNames) {
|
|
447
|
+
// Exact match → non-prefixed template resource
|
|
448
|
+
if (templateBaseNames.has(name))
|
|
449
|
+
return null;
|
|
450
|
+
// Try to match as prefixed
|
|
451
|
+
for (const base of templateBaseNames) {
|
|
452
|
+
if (name.endsWith(base) && name.length > base.length) {
|
|
453
|
+
return name.slice(0, name.length - base.length);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return undefined;
|
|
457
|
+
}
|
|
458
|
+
registerTemplateResources(prefix) {
|
|
459
|
+
if (!this.template)
|
|
460
|
+
return;
|
|
461
|
+
for (const q of this.template.queues ?? []) {
|
|
462
|
+
this.usageTracker.register(prefix + q.name, prefix);
|
|
463
|
+
}
|
|
464
|
+
for (const t of this.template.topics ?? []) {
|
|
465
|
+
this.usageTracker.register(prefix + t.name, prefix);
|
|
466
|
+
}
|
|
467
|
+
for (const entry of this.template.buckets ?? []) {
|
|
468
|
+
const name = typeof entry === "string" ? entry : entry.name;
|
|
469
|
+
this.usageTracker.register(prefix + name, prefix);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
touchAllInPrefix(prefix) {
|
|
473
|
+
const names = this.getResourceNamesForPrefix(prefix);
|
|
474
|
+
for (const name of names) {
|
|
475
|
+
this.usageTracker.touch(name);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
getResourceNamesForPrefix(prefix) {
|
|
479
|
+
if (!this.template)
|
|
480
|
+
return [];
|
|
481
|
+
const names = [];
|
|
482
|
+
for (const q of this.template.queues ?? []) {
|
|
483
|
+
names.push(prefix + q.name);
|
|
484
|
+
}
|
|
485
|
+
for (const t of this.template.topics ?? []) {
|
|
486
|
+
names.push(prefix + t.name);
|
|
487
|
+
}
|
|
488
|
+
for (const entry of this.template.buckets ?? []) {
|
|
489
|
+
const name = typeof entry === "string" ? entry : entry.name;
|
|
490
|
+
names.push(prefix + name);
|
|
491
|
+
}
|
|
492
|
+
return names;
|
|
493
|
+
}
|
|
494
|
+
// --- Private: Admin queue ---
|
|
495
|
+
createAdminQueue() {
|
|
496
|
+
if (!this.adminQueueName)
|
|
497
|
+
return;
|
|
498
|
+
const existing = this.sqsStore.getQueueByName(this.adminQueueName);
|
|
499
|
+
if (existing)
|
|
500
|
+
return;
|
|
501
|
+
const defaultHost = `127.0.0.1:${this.port}`;
|
|
502
|
+
const arn = sqsQueueArn(this.adminQueueName, this.region);
|
|
503
|
+
const url = this.sqsStore.buildQueueUrl(this.adminQueueName, String(this.port), defaultHost, this.region);
|
|
504
|
+
this.sqsStore.createQueue(this.adminQueueName, url, arn);
|
|
505
|
+
// Register as non-tenant-managed; always exempt from cleanup via isResourcePermanent()
|
|
506
|
+
this.usageTracker.register(this.adminQueueName, null);
|
|
507
|
+
}
|
|
508
|
+
pollAdminQueue() {
|
|
509
|
+
if (!this.adminQueueName)
|
|
510
|
+
return;
|
|
511
|
+
const queue = this.sqsStore.getQueueByName(this.adminQueueName);
|
|
512
|
+
if (!queue)
|
|
513
|
+
return;
|
|
514
|
+
const messages = queue.dequeue(10);
|
|
515
|
+
for (const msg of messages) {
|
|
516
|
+
try {
|
|
517
|
+
const request = JSON.parse(msg.Body);
|
|
518
|
+
if (request.action === "instantiate" && typeof request.prefix === "string") {
|
|
519
|
+
this.instantiateTemplate(request.prefix);
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
this.logger.warn(`Admin queue: ignoring message with unrecognized payload: ${msg.Body}`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
catch (err) {
|
|
526
|
+
this.logger.warn(`Admin queue: discarding invalid message: ${err instanceof Error ? err.message : err}`);
|
|
527
|
+
}
|
|
528
|
+
// Always delete the message (acknowledge)
|
|
529
|
+
queue.inflightMessages.delete(msg.ReceiptHandle);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
//# sourceMappingURL=tenantManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantManager.js","sourceRoot":"","sources":["../../src/tenant/tenantManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { FauxqsInitConfig } from "../initConfig.ts";
|
|
2
|
+
export interface TenantConfig {
|
|
3
|
+
/** TTL in milliseconds. Resources unused for longer than this are candidates for deletion. */
|
|
4
|
+
ttlMs: number;
|
|
5
|
+
/** How often to run the cleanup sweep, in milliseconds. Defaults to ttlMs / 10 (min 50ms). */
|
|
6
|
+
sweepIntervalMs?: number;
|
|
7
|
+
/** Max number of resources inspected per sweep tick. Defaults to 50. */
|
|
8
|
+
sweepBudget?: number;
|
|
9
|
+
/** Prefixes exempt from auto-cleanup. Include "" to make unprefixed / non-tenant-managed resources permanent. */
|
|
10
|
+
permanentPrefixes?: string[];
|
|
11
|
+
/** Explicit template config for prefixed instantiation. If omitted, uses the init config. */
|
|
12
|
+
template?: FauxqsInitConfig;
|
|
13
|
+
/** Enable the admin SQS queue for template instantiation via messages. true = default name "_fauxqs-admin", string = custom name. */
|
|
14
|
+
adminQueue?: boolean | string;
|
|
15
|
+
}
|
|
16
|
+
/** Message format for the admin SQS queue. */
|
|
17
|
+
export interface TemplateRequest {
|
|
18
|
+
action: "instantiate";
|
|
19
|
+
prefix: string;
|
|
20
|
+
}
|
|
21
|
+
/** Minimal logger interface for tenant internals. Console-backed by default. */
|
|
22
|
+
export interface TenantLogger {
|
|
23
|
+
warn(message: string): void;
|
|
24
|
+
}
|
|
25
|
+
export declare const defaultTenantLogger: TenantLogger;
|
|
26
|
+
//# sourceMappingURL=tenantTypes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantTypes.d.ts","sourceRoot":"","sources":["../../src/tenant/tenantTypes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,MAAM,WAAW,YAAY;IAC3B,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iHAAiH;IACjH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,qIAAqI;IACrI,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAC/B;AAED,8CAA8C;AAC9C,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,gFAAgF;AAChF,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,eAAO,MAAM,mBAAmB,EAAE,YAIjC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenantTypes.js","sourceRoot":"","sources":["../../src/tenant/tenantTypes.ts"],"names":[],"mappings":"AA4BA,MAAM,CAAC,MAAM,mBAAmB,GAAiB;IAC/C,IAAI,CAAC,OAAe;QAClB,OAAO,CAAC,IAAI,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;IAC7C,CAAC;CACF,CAAC"}
|