@mastra/google-cloud-pubsub 1.1.0-alpha.0 → 1.1.1-alpha.0
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/CHANGELOG.md +20 -0
- package/dist/index.cjs +34 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -20
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @mastra/inngest
|
|
2
2
|
|
|
3
|
+
## 1.1.1-alpha.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixed a startup race where concurrent subscribers to the same ungrouped topic could fail to attach. When a producer's `agent.stream()` and a consumer's `agent.observe()` subscribe to a fresh run topic within Google Cloud Pub/Sub's subscription-creation window, both raced to create the same subscription. The loser received an `ALREADY_EXISTS` error and, for ungrouped topics, fell through and threw `Failed to subscribe to topic`, killing the observe attach. Concurrent `init()` calls are now coalesced into a single create attempt, and an `ALREADY_EXISTS` result attaches to the existing subscription regardless of whether a group is set. ([#18252](https://github.com/mastra-ai/mastra/pull/18252))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`5bd72d2`](https://github.com/mastra-ai/mastra/commit/5bd72d255f45b5ea8ab342643bd463814a980a24), [`1cc9ee1`](https://github.com/mastra-ai/mastra/commit/1cc9ee1ba51db53020a735626d33017a60b4b5b3), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`30ebaf0`](https://github.com/mastra-ai/mastra/commit/30ebaf07bed5f4d30f2f257836c15d1bf7e40aae), [`5704634`](https://github.com/mastra-ai/mastra/commit/5704634b22133167dea337a942a34f57aaa3fa14), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`c0eda2b`](https://github.com/mastra-ai/mastra/commit/c0eda2bcd91a228427314b12c91d8b147f3a739f), [`c0eda2b`](https://github.com/mastra-ai/mastra/commit/c0eda2bcd91a228427314b12c91d8b147f3a739f), [`b13925b`](https://github.com/mastra-ai/mastra/commit/b13925bfa91aa8700f56fa54a9ce707ee7e4ba62), [`bf94ec6`](https://github.com/mastra-ai/mastra/commit/bf94ec68192d9f16e46ef7e5ac36370aeeddf35d), [`a29f371`](https://github.com/mastra-ai/mastra/commit/a29f371aef629ac8562661524a497127e93b5131), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`073f910`](https://github.com/mastra-ai/mastra/commit/073f910481e7d94b95ba3830f96531774ae95d33), [`ebbe1d3`](https://github.com/mastra-ai/mastra/commit/ebbe1d31a965a3adb0e728758f326b8122b4b55f), [`1f97ce5`](https://github.com/mastra-ai/mastra/commit/1f97ce5695463bebb4eaacf501da6fb403e20885), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`64f58c0`](https://github.com/mastra-ai/mastra/commit/64f58c04e78b40137497d47f781e897e416f22a5), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`ebbe1d3`](https://github.com/mastra-ai/mastra/commit/ebbe1d31a965a3adb0e728758f326b8122b4b55f), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`8e25a78`](https://github.com/mastra-ai/mastra/commit/8e25a78e0597575f0b0729bae8c5e190c84869b5), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`a5b22d3`](https://github.com/mastra-ai/mastra/commit/a5b22d314d62a68d801886a8d3d0eb6c089473db), [`417baae`](https://github.com/mastra-ai/mastra/commit/417baae40b995db5819c845036947f0c27dc1c00), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858), [`74955f9`](https://github.com/mastra-ai/mastra/commit/74955f9120cde8b1d8ce4399232b4033236be858)]:
|
|
10
|
+
- @mastra/core@1.46.0-alpha.0
|
|
11
|
+
|
|
12
|
+
## 1.1.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- Random bump ([#18178](https://github.com/mastra-ai/mastra/pull/18178))
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [[`7c0d868`](https://github.com/mastra-ai/mastra/commit/7c0d868d97d0fdbc04c14d0166dbf44d4c5a4a62), [`d9d2273`](https://github.com/mastra-ai/mastra/commit/d9d2273c702690c9a26eab2aebea879701d4355a), [`b04369d`](https://github.com/mastra-ai/mastra/commit/b04369d6b167c698ef103981171a8bf92808e756), [`8f3c262`](https://github.com/mastra-ai/mastra/commit/8f3c262587b335588a02d96b17fd6aca34c885b3)]:
|
|
21
|
+
- @mastra/core@1.45.0
|
|
22
|
+
|
|
3
23
|
## 1.1.0-alpha.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -10,6 +10,10 @@ var GoogleCloudPubSub = class extends events.PubSub {
|
|
|
10
10
|
ackBuffer = {};
|
|
11
11
|
activeSubscriptions = {};
|
|
12
12
|
activeCbs = {};
|
|
13
|
+
// Coalesces concurrent init() calls for the same subscription so racing
|
|
14
|
+
// subscribers (e.g. a producer stream and a consumer observe on the same
|
|
15
|
+
// run topic) share a single createTopic/createSubscription attempt.
|
|
16
|
+
inFlightInit = {};
|
|
13
17
|
// Tracks the actual anonymous message listener registered on each subscription,
|
|
14
18
|
// so we can remove it cleanly on the final unsubscribe.
|
|
15
19
|
messageListeners = {};
|
|
@@ -36,30 +40,40 @@ var GoogleCloudPubSub = class extends events.PubSub {
|
|
|
36
40
|
}
|
|
37
41
|
}
|
|
38
42
|
async init(topicName, group) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
const subscriptionKey = group ? `${topicName}:${group}` : topicName;
|
|
44
|
+
if (this.inFlightInit[subscriptionKey]) {
|
|
45
|
+
return this.inFlightInit[subscriptionKey];
|
|
42
46
|
}
|
|
43
47
|
const subscriptionName = this.getSubscriptionName(topicName, group);
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
const initPromise = (async () => {
|
|
49
|
+
try {
|
|
50
|
+
await this.pubsub.createTopic(topicName);
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {
|
|
55
|
+
enableMessageOrdering: true,
|
|
56
|
+
enableExactlyOnceDelivery: topicName === "workflows" || !!group
|
|
57
|
+
});
|
|
58
|
+
this.activeSubscriptions[subscriptionKey] = sub;
|
|
59
|
+
return sub;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const alreadyExists = error?.code === 6;
|
|
62
|
+
if (alreadyExists || group) {
|
|
63
|
+
try {
|
|
64
|
+
const sub = this.pubsub.subscription(subscriptionName);
|
|
65
|
+
this.activeSubscriptions[subscriptionKey] = sub;
|
|
66
|
+
return sub;
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
|
-
|
|
62
|
-
|
|
71
|
+
return void 0;
|
|
72
|
+
})().finally(() => {
|
|
73
|
+
delete this.inFlightInit[subscriptionKey];
|
|
74
|
+
});
|
|
75
|
+
this.inFlightInit[subscriptionKey] = initPromise;
|
|
76
|
+
return initPromise;
|
|
63
77
|
}
|
|
64
78
|
async destroy(topicName) {
|
|
65
79
|
const subName = this.getSubscriptionName(topicName);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["PubSub","PubSubClient","activeCbs","cb"],"mappings":"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","file":"index.cjs","sourcesContent":["import { PubSub as PubSubClient } from '@google-cloud/pubsub';\nimport type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';\nimport { PubSub } from '@mastra/core/events';\nimport type { Event, EventCallback, SubscribeOptions } from '@mastra/core/events';\n\nexport class GoogleCloudPubSub extends PubSub {\n private instanceId: string;\n private pubsub: PubSubClient;\n private ackBuffer: Record<string, Promise<any>> = {};\n private activeSubscriptions: Record<string, Subscription> = {};\n private activeCbs: Record<string, Set<EventCallback>> = {};\n // Tracks the actual anonymous message listener registered on each subscription,\n // so we can remove it cleanly on the final unsubscribe.\n private messageListeners: Record<string, (message: Message) => void> = {};\n\n constructor(config: ClientConfig) {\n super();\n this.pubsub = new PubSubClient(config);\n this.instanceId = crypto.randomUUID();\n }\n\n getSubscriptionName(topic: string, group?: string) {\n if (group) {\n return `${topic}-${group}`;\n }\n return `${topic}-${this.instanceId}`;\n }\n\n async ackMessage(topic: string, message: Message) {\n try {\n const ackResponse = Promise.race([message.ackWithResponse(), new Promise(resolve => setTimeout(resolve, 5000))]);\n this.ackBuffer[topic + '-' + message.id] = ackResponse.catch(() => {});\n await ackResponse;\n delete this.ackBuffer[topic + '-' + message.id];\n } catch (e) {\n console.error('Error acking message', e);\n }\n }\n\n async init(topicName: string, group?: string) {\n try {\n await this.pubsub.createTopic(topicName);\n } catch {\n // no-op\n }\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n try {\n const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // Subscription may already exist (e.g. shared group subscription created by another process).\n // Get the existing subscription instead.\n if (group) {\n try {\n const sub = this.pubsub.subscription(subscriptionName);\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // no-op\n }\n }\n }\n\n return undefined;\n }\n\n async destroy(topicName: string) {\n const subName = this.getSubscriptionName(topicName);\n delete this.activeSubscriptions[topicName];\n this.pubsub.subscription(subName).removeAllListeners();\n await this.pubsub.subscription(subName).close();\n await this.pubsub.subscription(subName).delete();\n await this.pubsub.topic(topicName).delete();\n }\n\n async publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n if (topicName.startsWith('workflow.events.')) {\n const parts = topicName.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topicName = 'workflow.events.v2';\n } else {\n topicName = 'workflow.events.v1';\n }\n }\n\n let topic = this.pubsub.topic(topicName);\n\n try {\n await topic.publishMessage({\n data: Buffer.from(JSON.stringify(event)),\n orderingKey: 'workflows',\n });\n } catch (e: any) {\n if (e.code === 5) {\n await this.pubsub.createTopic(topicName);\n await this.publish(topicName, event);\n } else {\n throw e;\n }\n }\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n if (topic.startsWith('workflow.events.')) {\n const parts = topic.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topic = 'workflow.events.v2';\n } else {\n topic = 'workflow.events.v1';\n }\n }\n\n const group = options?.group;\n // Use a composite key when group is set so grouped and non-grouped subscriptions\n // on the same topic don't collide\n const subscriptionKey = group ? `${topic}:${group}` : topic;\n\n // Update tracked callbacks\n const subscription = this.activeSubscriptions[subscriptionKey] ?? (await this.init(topic, group));\n if (!subscription) {\n throw new Error(`Failed to subscribe to topic: ${topic}`);\n }\n\n this.activeSubscriptions[subscriptionKey] = subscription;\n\n const activeCbs = this.activeCbs[subscriptionKey] ?? new Set();\n activeCbs.add(cb);\n this.activeCbs[subscriptionKey] = activeCbs;\n\n if (subscription.isOpen) {\n return;\n }\n\n const messageListener = async (message: Message) => {\n const event = JSON.parse(message.data.toString()) as Event;\n event.id = message.id;\n event.createdAt = message.publishTime;\n event.deliveryAttempt = message.deliveryAttempt ?? 1;\n\n try {\n const activeCbs = this.activeCbs[subscriptionKey] ?? [];\n for (const cb of activeCbs) {\n cb(\n event,\n async () => {\n try {\n await this.ackMessage(subscriptionKey, message);\n } catch (e) {\n console.error('Error acking message', e);\n }\n },\n async () => {\n try {\n message.nack();\n } catch (e) {\n console.error('Error nacking message', e);\n }\n },\n );\n }\n } catch (error) {\n console.error('Error processing event', error);\n }\n };\n\n this.messageListeners[subscriptionKey] = messageListener;\n subscription.on('message', messageListener);\n\n subscription.on('error', async error => {\n console.error('subscription error', error);\n });\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n // Check both grouped and non-grouped subscription keys for this callback\n const keysToCheck = [topic];\n for (const key of Object.keys(this.activeCbs)) {\n if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {\n keysToCheck.push(key);\n }\n }\n\n for (const subscriptionKey of keysToCheck) {\n const activeCbs = this.activeCbs[subscriptionKey];\n if (activeCbs?.has(cb)) {\n activeCbs.delete(cb);\n\n if (activeCbs.size === 0) {\n const subscription = this.activeSubscriptions[subscriptionKey];\n const listener = this.messageListeners[subscriptionKey];\n if (subscription) {\n if (listener) subscription.removeListener('message', listener);\n await subscription.close();\n }\n delete this.activeSubscriptions[subscriptionKey];\n delete this.activeCbs[subscriptionKey];\n delete this.messageListeners[subscriptionKey];\n }\n return;\n }\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(Object.values(this.ackBuffer));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["PubSub","PubSubClient","activeCbs","cb"],"mappings":"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","file":"index.cjs","sourcesContent":["import { PubSub as PubSubClient } from '@google-cloud/pubsub';\nimport type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';\nimport { PubSub } from '@mastra/core/events';\nimport type { Event, EventCallback, SubscribeOptions } from '@mastra/core/events';\n\nexport class GoogleCloudPubSub extends PubSub {\n private instanceId: string;\n private pubsub: PubSubClient;\n private ackBuffer: Record<string, Promise<any>> = {};\n private activeSubscriptions: Record<string, Subscription> = {};\n private activeCbs: Record<string, Set<EventCallback>> = {};\n // Coalesces concurrent init() calls for the same subscription so racing\n // subscribers (e.g. a producer stream and a consumer observe on the same\n // run topic) share a single createTopic/createSubscription attempt.\n private inFlightInit: Record<string, Promise<Subscription | undefined>> = {};\n // Tracks the actual anonymous message listener registered on each subscription,\n // so we can remove it cleanly on the final unsubscribe.\n private messageListeners: Record<string, (message: Message) => void> = {};\n\n constructor(config: ClientConfig) {\n super();\n this.pubsub = new PubSubClient(config);\n this.instanceId = crypto.randomUUID();\n }\n\n getSubscriptionName(topic: string, group?: string) {\n if (group) {\n return `${topic}-${group}`;\n }\n return `${topic}-${this.instanceId}`;\n }\n\n async ackMessage(topic: string, message: Message) {\n try {\n const ackResponse = Promise.race([message.ackWithResponse(), new Promise(resolve => setTimeout(resolve, 5000))]);\n this.ackBuffer[topic + '-' + message.id] = ackResponse.catch(() => {});\n await ackResponse;\n delete this.ackBuffer[topic + '-' + message.id];\n } catch (e) {\n console.error('Error acking message', e);\n }\n }\n\n async init(topicName: string, group?: string): Promise<Subscription | undefined> {\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n\n // Reuse an in-flight init so concurrent subscribers don't race to create the\n // same subscription. The promise is registered synchronously below (before any\n // await), so a second caller arriving during the create window reuses it.\n if (this.inFlightInit[subscriptionKey]) {\n return this.inFlightInit[subscriptionKey];\n }\n\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const initPromise = (async (): Promise<Subscription | undefined> => {\n try {\n await this.pubsub.createTopic(topicName);\n } catch {\n // no-op\n }\n try {\n const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch (error) {\n // The subscription may already exist: created concurrently by a racing\n // subscriber (ALREADY_EXISTS / gRPC code 6), shared by another process via\n // a group, or surviving a previous process. In all of these cases attach to\n // the existing subscription instead of failing. Ungrouped subscriptions hit\n // this on the concurrent-create race, so we must not gate it on `group`.\n const alreadyExists = (error as { code?: number } | undefined)?.code === 6;\n if (alreadyExists || group) {\n try {\n const sub = this.pubsub.subscription(subscriptionName);\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // no-op\n }\n }\n }\n return undefined;\n })().finally(() => {\n delete this.inFlightInit[subscriptionKey];\n });\n\n this.inFlightInit[subscriptionKey] = initPromise;\n return initPromise;\n }\n\n async destroy(topicName: string) {\n const subName = this.getSubscriptionName(topicName);\n delete this.activeSubscriptions[topicName];\n this.pubsub.subscription(subName).removeAllListeners();\n await this.pubsub.subscription(subName).close();\n await this.pubsub.subscription(subName).delete();\n await this.pubsub.topic(topicName).delete();\n }\n\n async publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n if (topicName.startsWith('workflow.events.')) {\n const parts = topicName.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topicName = 'workflow.events.v2';\n } else {\n topicName = 'workflow.events.v1';\n }\n }\n\n let topic = this.pubsub.topic(topicName);\n\n try {\n await topic.publishMessage({\n data: Buffer.from(JSON.stringify(event)),\n orderingKey: 'workflows',\n });\n } catch (e: any) {\n if (e.code === 5) {\n await this.pubsub.createTopic(topicName);\n await this.publish(topicName, event);\n } else {\n throw e;\n }\n }\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n if (topic.startsWith('workflow.events.')) {\n const parts = topic.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topic = 'workflow.events.v2';\n } else {\n topic = 'workflow.events.v1';\n }\n }\n\n const group = options?.group;\n // Use a composite key when group is set so grouped and non-grouped subscriptions\n // on the same topic don't collide\n const subscriptionKey = group ? `${topic}:${group}` : topic;\n\n // Update tracked callbacks\n const subscription = this.activeSubscriptions[subscriptionKey] ?? (await this.init(topic, group));\n if (!subscription) {\n throw new Error(`Failed to subscribe to topic: ${topic}`);\n }\n\n this.activeSubscriptions[subscriptionKey] = subscription;\n\n const activeCbs = this.activeCbs[subscriptionKey] ?? new Set();\n activeCbs.add(cb);\n this.activeCbs[subscriptionKey] = activeCbs;\n\n if (subscription.isOpen) {\n return;\n }\n\n const messageListener = async (message: Message) => {\n const event = JSON.parse(message.data.toString()) as Event;\n event.id = message.id;\n event.createdAt = message.publishTime;\n event.deliveryAttempt = message.deliveryAttempt ?? 1;\n\n try {\n const activeCbs = this.activeCbs[subscriptionKey] ?? [];\n for (const cb of activeCbs) {\n cb(\n event,\n async () => {\n try {\n await this.ackMessage(subscriptionKey, message);\n } catch (e) {\n console.error('Error acking message', e);\n }\n },\n async () => {\n try {\n message.nack();\n } catch (e) {\n console.error('Error nacking message', e);\n }\n },\n );\n }\n } catch (error) {\n console.error('Error processing event', error);\n }\n };\n\n this.messageListeners[subscriptionKey] = messageListener;\n subscription.on('message', messageListener);\n\n subscription.on('error', async error => {\n console.error('subscription error', error);\n });\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n // Check both grouped and non-grouped subscription keys for this callback\n const keysToCheck = [topic];\n for (const key of Object.keys(this.activeCbs)) {\n if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {\n keysToCheck.push(key);\n }\n }\n\n for (const subscriptionKey of keysToCheck) {\n const activeCbs = this.activeCbs[subscriptionKey];\n if (activeCbs?.has(cb)) {\n activeCbs.delete(cb);\n\n if (activeCbs.size === 0) {\n const subscription = this.activeSubscriptions[subscriptionKey];\n const listener = this.messageListeners[subscriptionKey];\n if (subscription) {\n if (listener) subscription.removeListener('message', listener);\n await subscription.close();\n }\n delete this.activeSubscriptions[subscriptionKey];\n delete this.activeCbs[subscriptionKey];\n delete this.messageListeners[subscriptionKey];\n }\n return;\n }\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(Object.values(this.ackBuffer));\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare class GoogleCloudPubSub extends PubSub {
|
|
|
7
7
|
private ackBuffer;
|
|
8
8
|
private activeSubscriptions;
|
|
9
9
|
private activeCbs;
|
|
10
|
+
private inFlightInit;
|
|
10
11
|
private messageListeners;
|
|
11
12
|
constructor(config: ClientConfig);
|
|
12
13
|
getSubscriptionName(topic: string, group?: string): string;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAElF,qBAAa,iBAAkB,SAAQ,MAAM;IAC3C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,SAAS,CAA0C;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAElF,qBAAa,iBAAkB,SAAQ,MAAM;IAC3C,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,SAAS,CAA0C;IAI3D,OAAO,CAAC,YAAY,CAAyD;IAG7E,OAAO,CAAC,gBAAgB,CAAkD;gBAE9D,MAAM,EAAE,YAAY;IAMhC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAO3C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAW1C,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;IAkD1E,OAAO,CAAC,SAAS,EAAE,MAAM;IASzB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BjF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAuEtF,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B5D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,10 @@ var GoogleCloudPubSub = class extends PubSub {
|
|
|
8
8
|
ackBuffer = {};
|
|
9
9
|
activeSubscriptions = {};
|
|
10
10
|
activeCbs = {};
|
|
11
|
+
// Coalesces concurrent init() calls for the same subscription so racing
|
|
12
|
+
// subscribers (e.g. a producer stream and a consumer observe on the same
|
|
13
|
+
// run topic) share a single createTopic/createSubscription attempt.
|
|
14
|
+
inFlightInit = {};
|
|
11
15
|
// Tracks the actual anonymous message listener registered on each subscription,
|
|
12
16
|
// so we can remove it cleanly on the final unsubscribe.
|
|
13
17
|
messageListeners = {};
|
|
@@ -34,30 +38,40 @@ var GoogleCloudPubSub = class extends PubSub {
|
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
async init(topicName, group) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
const subscriptionKey = group ? `${topicName}:${group}` : topicName;
|
|
42
|
+
if (this.inFlightInit[subscriptionKey]) {
|
|
43
|
+
return this.inFlightInit[subscriptionKey];
|
|
40
44
|
}
|
|
41
45
|
const subscriptionName = this.getSubscriptionName(topicName, group);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
const initPromise = (async () => {
|
|
47
|
+
try {
|
|
48
|
+
await this.pubsub.createTopic(topicName);
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {
|
|
53
|
+
enableMessageOrdering: true,
|
|
54
|
+
enableExactlyOnceDelivery: topicName === "workflows" || !!group
|
|
55
|
+
});
|
|
56
|
+
this.activeSubscriptions[subscriptionKey] = sub;
|
|
57
|
+
return sub;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
const alreadyExists = error?.code === 6;
|
|
60
|
+
if (alreadyExists || group) {
|
|
61
|
+
try {
|
|
62
|
+
const sub = this.pubsub.subscription(subscriptionName);
|
|
63
|
+
this.activeSubscriptions[subscriptionKey] = sub;
|
|
64
|
+
return sub;
|
|
65
|
+
} catch {
|
|
66
|
+
}
|
|
57
67
|
}
|
|
58
68
|
}
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
return void 0;
|
|
70
|
+
})().finally(() => {
|
|
71
|
+
delete this.inFlightInit[subscriptionKey];
|
|
72
|
+
});
|
|
73
|
+
this.inFlightInit[subscriptionKey] = initPromise;
|
|
74
|
+
return initPromise;
|
|
61
75
|
}
|
|
62
76
|
async destroy(topicName) {
|
|
63
77
|
const subName = this.getSubscriptionName(topicName);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["PubSubClient","activeCbs","cb"],"mappings":"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","file":"index.js","sourcesContent":["import { PubSub as PubSubClient } from '@google-cloud/pubsub';\nimport type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';\nimport { PubSub } from '@mastra/core/events';\nimport type { Event, EventCallback, SubscribeOptions } from '@mastra/core/events';\n\nexport class GoogleCloudPubSub extends PubSub {\n private instanceId: string;\n private pubsub: PubSubClient;\n private ackBuffer: Record<string, Promise<any>> = {};\n private activeSubscriptions: Record<string, Subscription> = {};\n private activeCbs: Record<string, Set<EventCallback>> = {};\n // Tracks the actual anonymous message listener registered on each subscription,\n // so we can remove it cleanly on the final unsubscribe.\n private messageListeners: Record<string, (message: Message) => void> = {};\n\n constructor(config: ClientConfig) {\n super();\n this.pubsub = new PubSubClient(config);\n this.instanceId = crypto.randomUUID();\n }\n\n getSubscriptionName(topic: string, group?: string) {\n if (group) {\n return `${topic}-${group}`;\n }\n return `${topic}-${this.instanceId}`;\n }\n\n async ackMessage(topic: string, message: Message) {\n try {\n const ackResponse = Promise.race([message.ackWithResponse(), new Promise(resolve => setTimeout(resolve, 5000))]);\n this.ackBuffer[topic + '-' + message.id] = ackResponse.catch(() => {});\n await ackResponse;\n delete this.ackBuffer[topic + '-' + message.id];\n } catch (e) {\n console.error('Error acking message', e);\n }\n }\n\n async init(topicName: string, group?: string) {\n try {\n await this.pubsub.createTopic(topicName);\n } catch {\n // no-op\n }\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n try {\n const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // Subscription may already exist (e.g. shared group subscription created by another process).\n // Get the existing subscription instead.\n if (group) {\n try {\n const sub = this.pubsub.subscription(subscriptionName);\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // no-op\n }\n }\n }\n\n return undefined;\n }\n\n async destroy(topicName: string) {\n const subName = this.getSubscriptionName(topicName);\n delete this.activeSubscriptions[topicName];\n this.pubsub.subscription(subName).removeAllListeners();\n await this.pubsub.subscription(subName).close();\n await this.pubsub.subscription(subName).delete();\n await this.pubsub.topic(topicName).delete();\n }\n\n async publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n if (topicName.startsWith('workflow.events.')) {\n const parts = topicName.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topicName = 'workflow.events.v2';\n } else {\n topicName = 'workflow.events.v1';\n }\n }\n\n let topic = this.pubsub.topic(topicName);\n\n try {\n await topic.publishMessage({\n data: Buffer.from(JSON.stringify(event)),\n orderingKey: 'workflows',\n });\n } catch (e: any) {\n if (e.code === 5) {\n await this.pubsub.createTopic(topicName);\n await this.publish(topicName, event);\n } else {\n throw e;\n }\n }\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n if (topic.startsWith('workflow.events.')) {\n const parts = topic.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topic = 'workflow.events.v2';\n } else {\n topic = 'workflow.events.v1';\n }\n }\n\n const group = options?.group;\n // Use a composite key when group is set so grouped and non-grouped subscriptions\n // on the same topic don't collide\n const subscriptionKey = group ? `${topic}:${group}` : topic;\n\n // Update tracked callbacks\n const subscription = this.activeSubscriptions[subscriptionKey] ?? (await this.init(topic, group));\n if (!subscription) {\n throw new Error(`Failed to subscribe to topic: ${topic}`);\n }\n\n this.activeSubscriptions[subscriptionKey] = subscription;\n\n const activeCbs = this.activeCbs[subscriptionKey] ?? new Set();\n activeCbs.add(cb);\n this.activeCbs[subscriptionKey] = activeCbs;\n\n if (subscription.isOpen) {\n return;\n }\n\n const messageListener = async (message: Message) => {\n const event = JSON.parse(message.data.toString()) as Event;\n event.id = message.id;\n event.createdAt = message.publishTime;\n event.deliveryAttempt = message.deliveryAttempt ?? 1;\n\n try {\n const activeCbs = this.activeCbs[subscriptionKey] ?? [];\n for (const cb of activeCbs) {\n cb(\n event,\n async () => {\n try {\n await this.ackMessage(subscriptionKey, message);\n } catch (e) {\n console.error('Error acking message', e);\n }\n },\n async () => {\n try {\n message.nack();\n } catch (e) {\n console.error('Error nacking message', e);\n }\n },\n );\n }\n } catch (error) {\n console.error('Error processing event', error);\n }\n };\n\n this.messageListeners[subscriptionKey] = messageListener;\n subscription.on('message', messageListener);\n\n subscription.on('error', async error => {\n console.error('subscription error', error);\n });\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n // Check both grouped and non-grouped subscription keys for this callback\n const keysToCheck = [topic];\n for (const key of Object.keys(this.activeCbs)) {\n if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {\n keysToCheck.push(key);\n }\n }\n\n for (const subscriptionKey of keysToCheck) {\n const activeCbs = this.activeCbs[subscriptionKey];\n if (activeCbs?.has(cb)) {\n activeCbs.delete(cb);\n\n if (activeCbs.size === 0) {\n const subscription = this.activeSubscriptions[subscriptionKey];\n const listener = this.messageListeners[subscriptionKey];\n if (subscription) {\n if (listener) subscription.removeListener('message', listener);\n await subscription.close();\n }\n delete this.activeSubscriptions[subscriptionKey];\n delete this.activeCbs[subscriptionKey];\n delete this.messageListeners[subscriptionKey];\n }\n return;\n }\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(Object.values(this.ackBuffer));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["PubSubClient","activeCbs","cb"],"mappings":"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","file":"index.js","sourcesContent":["import { PubSub as PubSubClient } from '@google-cloud/pubsub';\nimport type { ClientConfig, Message, Subscription } from '@google-cloud/pubsub';\nimport { PubSub } from '@mastra/core/events';\nimport type { Event, EventCallback, SubscribeOptions } from '@mastra/core/events';\n\nexport class GoogleCloudPubSub extends PubSub {\n private instanceId: string;\n private pubsub: PubSubClient;\n private ackBuffer: Record<string, Promise<any>> = {};\n private activeSubscriptions: Record<string, Subscription> = {};\n private activeCbs: Record<string, Set<EventCallback>> = {};\n // Coalesces concurrent init() calls for the same subscription so racing\n // subscribers (e.g. a producer stream and a consumer observe on the same\n // run topic) share a single createTopic/createSubscription attempt.\n private inFlightInit: Record<string, Promise<Subscription | undefined>> = {};\n // Tracks the actual anonymous message listener registered on each subscription,\n // so we can remove it cleanly on the final unsubscribe.\n private messageListeners: Record<string, (message: Message) => void> = {};\n\n constructor(config: ClientConfig) {\n super();\n this.pubsub = new PubSubClient(config);\n this.instanceId = crypto.randomUUID();\n }\n\n getSubscriptionName(topic: string, group?: string) {\n if (group) {\n return `${topic}-${group}`;\n }\n return `${topic}-${this.instanceId}`;\n }\n\n async ackMessage(topic: string, message: Message) {\n try {\n const ackResponse = Promise.race([message.ackWithResponse(), new Promise(resolve => setTimeout(resolve, 5000))]);\n this.ackBuffer[topic + '-' + message.id] = ackResponse.catch(() => {});\n await ackResponse;\n delete this.ackBuffer[topic + '-' + message.id];\n } catch (e) {\n console.error('Error acking message', e);\n }\n }\n\n async init(topicName: string, group?: string): Promise<Subscription | undefined> {\n const subscriptionKey = group ? `${topicName}:${group}` : topicName;\n\n // Reuse an in-flight init so concurrent subscribers don't race to create the\n // same subscription. The promise is registered synchronously below (before any\n // await), so a second caller arriving during the create window reuses it.\n if (this.inFlightInit[subscriptionKey]) {\n return this.inFlightInit[subscriptionKey];\n }\n\n const subscriptionName = this.getSubscriptionName(topicName, group);\n const initPromise = (async (): Promise<Subscription | undefined> => {\n try {\n await this.pubsub.createTopic(topicName);\n } catch {\n // no-op\n }\n try {\n const [sub] = await this.pubsub.topic(topicName).createSubscription(subscriptionName, {\n enableMessageOrdering: true,\n enableExactlyOnceDelivery: topicName === 'workflows' || !!group,\n });\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch (error) {\n // The subscription may already exist: created concurrently by a racing\n // subscriber (ALREADY_EXISTS / gRPC code 6), shared by another process via\n // a group, or surviving a previous process. In all of these cases attach to\n // the existing subscription instead of failing. Ungrouped subscriptions hit\n // this on the concurrent-create race, so we must not gate it on `group`.\n const alreadyExists = (error as { code?: number } | undefined)?.code === 6;\n if (alreadyExists || group) {\n try {\n const sub = this.pubsub.subscription(subscriptionName);\n this.activeSubscriptions[subscriptionKey] = sub;\n return sub;\n } catch {\n // no-op\n }\n }\n }\n return undefined;\n })().finally(() => {\n delete this.inFlightInit[subscriptionKey];\n });\n\n this.inFlightInit[subscriptionKey] = initPromise;\n return initPromise;\n }\n\n async destroy(topicName: string) {\n const subName = this.getSubscriptionName(topicName);\n delete this.activeSubscriptions[topicName];\n this.pubsub.subscription(subName).removeAllListeners();\n await this.pubsub.subscription(subName).close();\n await this.pubsub.subscription(subName).delete();\n await this.pubsub.topic(topicName).delete();\n }\n\n async publish(topicName: string, event: Omit<Event, 'id' | 'createdAt'>): Promise<void> {\n if (topicName.startsWith('workflow.events.')) {\n const parts = topicName.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topicName = 'workflow.events.v2';\n } else {\n topicName = 'workflow.events.v1';\n }\n }\n\n let topic = this.pubsub.topic(topicName);\n\n try {\n await topic.publishMessage({\n data: Buffer.from(JSON.stringify(event)),\n orderingKey: 'workflows',\n });\n } catch (e: any) {\n if (e.code === 5) {\n await this.pubsub.createTopic(topicName);\n await this.publish(topicName, event);\n } else {\n throw e;\n }\n }\n }\n\n async subscribe(topic: string, cb: EventCallback, options?: SubscribeOptions): Promise<void> {\n if (topic.startsWith('workflow.events.')) {\n const parts = topic.split('.');\n if (parts[parts.length - 2] === 'v2') {\n topic = 'workflow.events.v2';\n } else {\n topic = 'workflow.events.v1';\n }\n }\n\n const group = options?.group;\n // Use a composite key when group is set so grouped and non-grouped subscriptions\n // on the same topic don't collide\n const subscriptionKey = group ? `${topic}:${group}` : topic;\n\n // Update tracked callbacks\n const subscription = this.activeSubscriptions[subscriptionKey] ?? (await this.init(topic, group));\n if (!subscription) {\n throw new Error(`Failed to subscribe to topic: ${topic}`);\n }\n\n this.activeSubscriptions[subscriptionKey] = subscription;\n\n const activeCbs = this.activeCbs[subscriptionKey] ?? new Set();\n activeCbs.add(cb);\n this.activeCbs[subscriptionKey] = activeCbs;\n\n if (subscription.isOpen) {\n return;\n }\n\n const messageListener = async (message: Message) => {\n const event = JSON.parse(message.data.toString()) as Event;\n event.id = message.id;\n event.createdAt = message.publishTime;\n event.deliveryAttempt = message.deliveryAttempt ?? 1;\n\n try {\n const activeCbs = this.activeCbs[subscriptionKey] ?? [];\n for (const cb of activeCbs) {\n cb(\n event,\n async () => {\n try {\n await this.ackMessage(subscriptionKey, message);\n } catch (e) {\n console.error('Error acking message', e);\n }\n },\n async () => {\n try {\n message.nack();\n } catch (e) {\n console.error('Error nacking message', e);\n }\n },\n );\n }\n } catch (error) {\n console.error('Error processing event', error);\n }\n };\n\n this.messageListeners[subscriptionKey] = messageListener;\n subscription.on('message', messageListener);\n\n subscription.on('error', async error => {\n console.error('subscription error', error);\n });\n }\n\n async unsubscribe(topic: string, cb: EventCallback): Promise<void> {\n // Check both grouped and non-grouped subscription keys for this callback\n const keysToCheck = [topic];\n for (const key of Object.keys(this.activeCbs)) {\n if (key.startsWith(`${topic}:`) && !keysToCheck.includes(key)) {\n keysToCheck.push(key);\n }\n }\n\n for (const subscriptionKey of keysToCheck) {\n const activeCbs = this.activeCbs[subscriptionKey];\n if (activeCbs?.has(cb)) {\n activeCbs.delete(cb);\n\n if (activeCbs.size === 0) {\n const subscription = this.activeSubscriptions[subscriptionKey];\n const listener = this.messageListeners[subscriptionKey];\n if (subscription) {\n if (listener) subscription.removeListener('message', listener);\n await subscription.close();\n }\n delete this.activeSubscriptions[subscriptionKey];\n delete this.activeCbs[subscriptionKey];\n delete this.messageListeners[subscriptionKey];\n }\n return;\n }\n }\n }\n\n async flush(): Promise<void> {\n await Promise.all(Object.values(this.ackBuffer));\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/google-cloud-pubsub",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1-alpha.0",
|
|
4
4
|
"description": "Mastra Google Cloud PubSub integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -38,11 +38,11 @@
|
|
|
38
38
|
"tsup": "^8.5.1",
|
|
39
39
|
"typescript": "^6.0.3",
|
|
40
40
|
"vitest": "4.1.8",
|
|
41
|
-
"@internal/lint": "0.0.
|
|
42
|
-
"@internal/types-builder": "0.0.
|
|
43
|
-
"@mastra/
|
|
44
|
-
"@mastra/deployer": "1.
|
|
45
|
-
"@mastra/
|
|
41
|
+
"@internal/lint": "0.0.107",
|
|
42
|
+
"@internal/types-builder": "0.0.82",
|
|
43
|
+
"@mastra/core": "1.46.0-alpha.0",
|
|
44
|
+
"@mastra/deployer": "1.46.0-alpha.0",
|
|
45
|
+
"@mastra/libsql": "1.14.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@mastra/core": ">=1.13.2-0 <2.0.0-0"
|