@nebulae/event-store-tpi-rx6 1.1.5 → 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.
@@ -21,30 +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$() {
31
- return new Rx.Observable(async (observer) => {
33
+ start$() {
34
+ return new Rx.Observable(async (observer) => {
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
+
32
45
  try {
33
- const [topic] = await this.pubsubClient.createTopic(this.eventsTopic);
34
- console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker created topic: Topic=${this.eventsTopic}`);
35
- this.topic = topic;
36
- } catch (error) {
37
- if(error.code === 6) {
38
- this.topic = this.pubsubClient.topic(this.eventsTopic);
39
- console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker topic already exists, getting existing topic: Topic=${this.eventsTopic}`);
40
- } else {
41
- observer.error(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker failed to create or get topic: Topic=${this.eventsTopic}, Error=${error.message}`);
42
- return;
43
- }
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;
44
67
  }
45
- this.startMessageListener(this.topic);
46
- observer.next(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker listening: Topic=${this.eventsTopic}, subscriptionName=${this.eventsTopicSubscription}`);
47
- observer.complete();
48
68
  });
49
69
  }
50
70
 
@@ -53,7 +73,9 @@ class PubSubBroker {
53
73
  */
54
74
  stop$() {
55
75
  return Rx.Observable.create(observer => {
56
- Rx.defer(() => this.getSubscription$()).subscribe(
76
+ Rx.defer(() => this.getSubscription$()).pipe(
77
+ filter(sub => sub != null)
78
+ ).subscribe(
57
79
  (subscription) => {
58
80
  subscription.removeListener(`message`, this.onMessage);
59
81
  observer.next(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker removed listener: Topic=${this.eventsTopic}, subscriptionName=${subscription}`);
@@ -93,28 +115,41 @@ class PubSubBroker {
93
115
  getEventListener$(aggregateType, ignoreSelfEvents = true) {
94
116
  return this.orderedIncomingEvents$.pipe(
95
117
  filter(msg => msg)
96
- ,filter(msg => !ignoreSelfEvents || msg.attributes.senderId !== this.senderId)
97
- ,map(msg => msg.data)
98
- ,filter(evt => evt.at === aggregateType || aggregateType == "*")
99
- )
118
+ , filter(msg => !ignoreSelfEvents || msg.attributes.senderId !== this.senderId)
119
+ , map(msg => msg.data)
120
+ , filter(evt => evt.at === aggregateType || aggregateType == "*")
121
+ )
100
122
  }
101
123
 
102
124
 
103
125
  /**
104
126
  * Returns an Observable that resolves to the subscription
127
+ * Uses a semaphore to prevent concurrent access - returns null if busy
105
128
  */
106
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
+
107
139
  try {
108
140
  const [subscription] = await (topic || this.topic).createSubscription(this.eventsTopicSubscription);
109
141
  console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker created subscription: Topic=${this.eventsTopic}, subscriptionName=${this.eventsTopicSubscription}`);
110
- return subscription;
142
+ return subscription;
111
143
  } catch (error) {
112
- if(error.code === 6) {
144
+ if (error.code === 6) {
113
145
  console.log(`@nebulae/event-store-tpi-rx6: Event Store PubSub Broker subscription already exists, getting existing subscription: Topic=${this.eventsTopic}, subscriptionName=${this.eventsTopicSubscription}`);
114
146
  return (topic || this.topic).subscription(this.eventsTopicSubscription);
115
147
  } else {
116
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}`);
117
149
  }
150
+ } finally {
151
+ // Release lock
152
+ this.subscriptionLock = false;
118
153
  }
119
154
  }
120
155
 
@@ -122,30 +157,31 @@ class PubSubBroker {
122
157
  * Starts to listen messages
123
158
  */
124
159
  startMessageListener(topic) {
125
- this.messageListenerSubscription = Rx.defer(() => this.getSubscription$(topic))
126
- .subscribe(
127
- (pubSubSubscription) => {
128
- this.onMessage = message => {
129
- message.ack();
130
- this.incomingEvents$.next({
131
- data: JSON.parse(message.data),
132
- id: message.id,
133
- attributes: message.attributes,
134
- correlationId: message.attributes.correlationId
135
- });
136
- };
137
- pubSubSubscription.on(`message`, this.onMessage);
138
- pubSubSubscription.on('error', error => {
139
- 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
140
171
  });
141
- },
142
- (err) => {
143
- console.error('Failed to obtain EventStore subscription', err);
144
- },
145
- () => {
146
- console.log('GatewayEvents listener has completed!');
147
- }
148
- );
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
+ );
149
185
  }
150
186
 
151
187
  }
package/package.json CHANGED
@@ -64,5 +64,5 @@
64
64
  "scripts": {
65
65
  "test": "mocha --recursive --reporter spec"
66
66
  },
67
- "version": "1.1.5"
67
+ "version": "1.2.0"
68
68
  }