@nebulae/event-store-tpi-rx6 1.1.4 → 1.2.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/lib/broker/PubSubBroker.js +95 -39
- package/package.json +1 -1
|
@@ -21,19 +21,50 @@ class PubSubBroker {
|
|
|
21
21
|
)
|
|
22
22
|
this.senderId = uuidv4();
|
|
23
23
|
this.pubsubClient = new PubSub({});
|
|
24
|
+
this.subscriptionLock = false;
|
|
25
|
+
this.startLock = false;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Starts Broker connections
|
|
28
30
|
* Returns an Obserable that resolves to each connection result
|
|
31
|
+
* Uses a semaphore to prevent concurrent access - returns of(null) if busy
|
|
29
32
|
*/
|
|
30
|
-
start$() {
|
|
33
|
+
start$() {
|
|
31
34
|
return new Rx.Observable(async (observer) => {
|
|
32
|
-
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
// Check semaphore - return null if already busy
|
|
36
|
+
if (this.startLock) {
|
|
37
|
+
observer.next(null);
|
|
38
|
+
observer.complete();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Acquire lock
|
|
43
|
+
this.startLock = true;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
try {
|
|
47
|
+
const [topic] = await this.pubsubClient.createTopic(this.eventsTopic);
|
|
48
|
+
console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker created topic: Topic=${this.eventsTopic}`);
|
|
49
|
+
this.topic = topic;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (error.code === 6) {
|
|
52
|
+
this.topic = this.pubsubClient.topic(this.eventsTopic);
|
|
53
|
+
console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker topic already exists, getting existing topic: Topic=${this.eventsTopic}`);
|
|
54
|
+
} else {
|
|
55
|
+
observer.error(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker failed to create or get topic: Topic=${this.eventsTopic}, Error=${error.message}`);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (this.topic) {
|
|
60
|
+
this.startMessageListener(this.topic);
|
|
61
|
+
observer.next(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker listening: Topic=${this.eventsTopic}, subscriptionName=${this.eventsTopicSubscription}`);
|
|
62
|
+
}
|
|
63
|
+
observer.complete();
|
|
64
|
+
} finally {
|
|
65
|
+
// Release lock
|
|
66
|
+
this.startLock = false;
|
|
67
|
+
}
|
|
37
68
|
});
|
|
38
69
|
}
|
|
39
70
|
|
|
@@ -42,10 +73,12 @@ class PubSubBroker {
|
|
|
42
73
|
*/
|
|
43
74
|
stop$() {
|
|
44
75
|
return Rx.Observable.create(observer => {
|
|
45
|
-
this.getSubscription$().
|
|
76
|
+
Rx.defer(() => this.getSubscription$()).pipe(
|
|
77
|
+
filter(sub => sub != null)
|
|
78
|
+
).subscribe(
|
|
46
79
|
(subscription) => {
|
|
47
80
|
subscription.removeListener(`message`, this.onMessage);
|
|
48
|
-
observer.next(
|
|
81
|
+
observer.next(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker removed listener: Topic=${this.eventsTopic}, subscriptionName=${subscription}`);
|
|
49
82
|
},
|
|
50
83
|
(error) => observer.error(error),
|
|
51
84
|
() => {
|
|
@@ -82,50 +115,73 @@ class PubSubBroker {
|
|
|
82
115
|
getEventListener$(aggregateType, ignoreSelfEvents = true) {
|
|
83
116
|
return this.orderedIncomingEvents$.pipe(
|
|
84
117
|
filter(msg => msg)
|
|
85
|
-
,filter(msg => !ignoreSelfEvents || msg.attributes.senderId !== this.senderId)
|
|
86
|
-
,map(msg => msg.data)
|
|
87
|
-
,filter(evt => evt.at === aggregateType || aggregateType == "*")
|
|
88
|
-
|
|
118
|
+
, filter(msg => !ignoreSelfEvents || msg.attributes.senderId !== this.senderId)
|
|
119
|
+
, map(msg => msg.data)
|
|
120
|
+
, filter(evt => evt.at === aggregateType || aggregateType == "*")
|
|
121
|
+
)
|
|
89
122
|
}
|
|
90
123
|
|
|
91
124
|
|
|
92
125
|
/**
|
|
93
126
|
* Returns an Observable that resolves to the subscription
|
|
127
|
+
* Uses a semaphore to prevent concurrent access - returns null if busy
|
|
94
128
|
*/
|
|
95
|
-
getSubscription$(topic) {
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
|
|
129
|
+
async getSubscription$(topic) {
|
|
130
|
+
// Check semaphore - return null if already busy
|
|
131
|
+
if (this.subscriptionLock) {
|
|
132
|
+
//console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker getSubscription$ is busy, returning null`);
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Acquire lock
|
|
137
|
+
this.subscriptionLock = true;
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
const [subscription] = await (topic || this.topic).createSubscription(this.eventsTopicSubscription);
|
|
141
|
+
console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker created subscription: Topic=${this.eventsTopic}, subscriptionName=${this.eventsTopicSubscription}`);
|
|
142
|
+
return subscription;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
if (error.code === 6) {
|
|
145
|
+
console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker subscription already exists, getting existing subscription: Topic=${this.eventsTopic}, subscriptionName=${this.eventsTopicSubscription}`);
|
|
146
|
+
return (topic || this.topic).subscription(this.eventsTopicSubscription);
|
|
147
|
+
} else {
|
|
148
|
+
throw new Error(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker failed to create or get subscription: Topic=${this.eventsTopic}, subscriptionName=${this.eventsTopicSubscription}, Error=${error.message}`);
|
|
149
|
+
}
|
|
150
|
+
} finally {
|
|
151
|
+
// Release lock
|
|
152
|
+
this.subscriptionLock = false;
|
|
153
|
+
}
|
|
99
154
|
}
|
|
100
155
|
|
|
101
156
|
/**
|
|
102
157
|
* Starts to listen messages
|
|
103
158
|
*/
|
|
104
159
|
startMessageListener(topic) {
|
|
105
|
-
this.messageListenerSubscription = this.getSubscription$(topic)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
};
|
|
117
|
-
pubSubSubscription.on(`message`, this.onMessage);
|
|
118
|
-
pubSubSubscription.on('error', error => {
|
|
119
|
-
console.error('@nebulae/event-store-tpi-rx6.PubSubBroker: Received error:', error);
|
|
160
|
+
this.messageListenerSubscription = Rx.defer(() => this.getSubscription$(topic)).pipe(
|
|
161
|
+
filter(sub => sub != null)
|
|
162
|
+
).subscribe(
|
|
163
|
+
(pubSubSubscription) => {
|
|
164
|
+
this.onMessage = message => {
|
|
165
|
+
message.ack();
|
|
166
|
+
this.incomingEvents$.next({
|
|
167
|
+
data: JSON.parse(message.data),
|
|
168
|
+
id: message.id,
|
|
169
|
+
attributes: message.attributes,
|
|
170
|
+
correlationId: message.attributes.correlationId
|
|
120
171
|
});
|
|
121
|
-
}
|
|
122
|
-
(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
172
|
+
};
|
|
173
|
+
pubSubSubscription.on(`message`, this.onMessage);
|
|
174
|
+
pubSubSubscription.on('error', error => {
|
|
175
|
+
console.error('@nebulae/event-store-tpi-rx6.PubSubBroker: Received error:', error);
|
|
176
|
+
});
|
|
177
|
+
},
|
|
178
|
+
(err) => {
|
|
179
|
+
console.error('Failed to obtain EventStore subscription', err);
|
|
180
|
+
},
|
|
181
|
+
() => {
|
|
182
|
+
console.log('GatewayEvents listener has completed!');
|
|
183
|
+
}
|
|
184
|
+
);
|
|
129
185
|
}
|
|
130
186
|
|
|
131
187
|
}
|
package/package.json
CHANGED