@usherlabs/cex-broker 0.2.25 → 0.2.26

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.
@@ -332420,6 +332420,59 @@ function createExecuteActionHandler(deps) {
332420
332420
  }
332421
332421
  };
332422
332422
  }
332423
+ // src/handlers/subscribe/broker-lifecycle.ts
332424
+ class SubscribeBrokerLifecycle {
332425
+ #brokers = new Map;
332426
+ #closing = new Map;
332427
+ #shuttingDown = false;
332428
+ register(broker, context2) {
332429
+ this.#brokers.set(broker, context2);
332430
+ if (this.#shuttingDown) {
332431
+ this.close(broker);
332432
+ }
332433
+ }
332434
+ close(broker) {
332435
+ const existing = this.#closing.get(broker);
332436
+ if (existing) {
332437
+ return existing;
332438
+ }
332439
+ const context2 = this.#brokers.get(broker) ?? {
332440
+ cex: "unknown",
332441
+ symbol: "unknown"
332442
+ };
332443
+ this.#brokers.delete(broker);
332444
+ const closing = (async () => {
332445
+ try {
332446
+ await broker.close();
332447
+ log.debug("Request-scoped Subscribe broker closed", context2);
332448
+ return "closed";
332449
+ } catch (error48) {
332450
+ log.warn("Failed to close request-scoped Subscribe broker", {
332451
+ ...context2,
332452
+ error: error48
332453
+ });
332454
+ return "failed";
332455
+ } finally {
332456
+ this.#closing.delete(broker);
332457
+ }
332458
+ })();
332459
+ this.#closing.set(broker, closing);
332460
+ return closing;
332461
+ }
332462
+ async closeAll() {
332463
+ this.#shuttingDown = true;
332464
+ let failed = 0;
332465
+ while (this.#brokers.size > 0 || this.#closing.size > 0) {
332466
+ const inFlight = [...this.#closing.values()];
332467
+ const fresh = [...this.#brokers.keys()].map((broker) => this.close(broker));
332468
+ const outcomes = await Promise.all([...fresh, ...inFlight]);
332469
+ failed += outcomes.filter((outcome) => outcome === "failed").length;
332470
+ }
332471
+ if (failed > 0) {
332472
+ throw new Error(`${failed} request-scoped Subscribe broker(s) failed to close`);
332473
+ }
332474
+ }
332475
+ }
332423
332476
  // src/handlers/subscribe/handler.ts
332424
332477
  var grpc13 = __toESM(require_src3(), 1);
332425
332478
 
@@ -333496,15 +333549,34 @@ async function runCcxtSubscribeLoop(call, isClosed, symbol2, subscriptionType, w
333496
333549
  }
333497
333550
  function createSubscribeHandler(deps) {
333498
333551
  const { brokers, whitelistIps, otelMetrics, brokerArchiver } = deps;
333552
+ const brokerLifecycle = deps.brokerLifecycle ?? new SubscribeBrokerLifecycle;
333499
333553
  return async (call) => {
333500
333554
  const subscribeStartTime = Date.now();
333501
333555
  let streamClosed = false;
333556
+ let ownedBroker = null;
333557
+ let ownedBrokerClosePromise;
333502
333558
  const markStreamClosed = () => {
333503
333559
  streamClosed = true;
333504
333560
  };
333505
- const isStreamClosed = () => streamClosed || call.destroyed;
333506
- call.once("close", markStreamClosed);
333561
+ const isStreamClosed = () => streamClosed || call.cancelled || call.writableEnded;
333562
+ const closeOwnedBroker = () => {
333563
+ if (ownedBrokerClosePromise) {
333564
+ return ownedBrokerClosePromise;
333565
+ }
333566
+ if (!ownedBroker) {
333567
+ return Promise.resolve();
333568
+ }
333569
+ const broker = ownedBroker;
333570
+ ownedBroker = null;
333571
+ ownedBrokerClosePromise = brokerLifecycle.close(broker);
333572
+ return ownedBrokerClosePromise;
333573
+ };
333574
+ const closeOwnedBrokerOnCallEnd = () => {
333575
+ closeOwnedBroker();
333576
+ };
333507
333577
  call.once("cancelled", markStreamClosed);
333578
+ call.once("cancelled", closeOwnedBrokerOnCallEnd);
333579
+ call.once("error", closeOwnedBrokerOnCallEnd);
333508
333580
  call.once("end", () => {
333509
333581
  markStreamClosed();
333510
333582
  log.info("Subscribe stream ended");
@@ -333576,6 +333648,17 @@ function createSubscribeHandler(deps) {
333576
333648
  });
333577
333649
  return;
333578
333650
  }
333651
+ if (!selectedBrokerAccount) {
333652
+ ownedBroker = broker;
333653
+ brokerLifecycle.register(broker, {
333654
+ cex: normalizedCex,
333655
+ symbol: symbol2
333656
+ });
333657
+ if (isStreamClosed()) {
333658
+ await closeOwnedBroker();
333659
+ return;
333660
+ }
333661
+ }
333579
333662
  const resolvedSymbol = await resolveSubscriptionSymbol(broker, symbol2, options?.marketType);
333580
333663
  const assetType = parseMarketType(options?.marketType);
333581
333664
  const deploymentId = brokerArchiver?.getDeploymentId() ?? "unknown";
@@ -333840,6 +333923,10 @@ function createSubscribeHandler(deps) {
333840
333923
  symbol: "",
333841
333924
  type: subscriptionType
333842
333925
  });
333926
+ } finally {
333927
+ call.off("cancelled", closeOwnedBrokerOnCallEnd);
333928
+ call.off("error", closeOwnedBrokerOnCallEnd);
333929
+ await closeOwnedBroker();
333843
333930
  }
333844
333931
  };
333845
333932
  }
@@ -333990,7 +334077,7 @@ var CEX_BROKER_PACKAGE_DEFINITION = protoLoader.fromJSON(node_descriptor_default
333990
334077
  // src/server.ts
333991
334078
  var grpcObj = grpc14.loadPackageDefinition(CEX_BROKER_PACKAGE_DEFINITION);
333992
334079
  var cexNode = grpcObj.cex_broker;
333993
- function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, otelMetrics, brokerArchiver, orderActivityTracker, withdrawalObservationTracker) {
334080
+ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, otelMetrics, brokerArchiver, orderActivityTracker, withdrawalObservationTracker, subscribeBrokerLifecycle) {
333994
334081
  const server = new grpc14.Server;
333995
334082
  server.addService(cexNode.cex_service.service, {
333996
334083
  ExecuteAction: createExecuteActionHandler({
@@ -334008,7 +334095,8 @@ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, ot
334008
334095
  brokers,
334009
334096
  whitelistIps,
334010
334097
  otelMetrics,
334011
- brokerArchiver
334098
+ brokerArchiver,
334099
+ brokerLifecycle: subscribeBrokerLifecycle
334012
334100
  })
334013
334101
  });
334014
334102
  return server;
@@ -0,0 +1,13 @@
1
+ import type { Exchange } from "@usherlabs/ccxt";
2
+ type BrokerContext = {
3
+ cex: string;
4
+ symbol: string;
5
+ };
6
+ export type BrokerCloseOutcome = "closed" | "failed";
7
+ export declare class SubscribeBrokerLifecycle {
8
+ #private;
9
+ register(broker: Exchange, context: BrokerContext): void;
10
+ close(broker: Exchange): Promise<BrokerCloseOutcome>;
11
+ closeAll(): Promise<void>;
12
+ }
13
+ export {};
@@ -3,11 +3,13 @@ import { type BrokerPoolEntry } from "../../helpers/broker";
3
3
  import type { BrokerExecutionArchiver } from "../../helpers/broker-execution-archive";
4
4
  import type { OtelMetrics } from "../../helpers/otel";
5
5
  import type { SubscribeRequest, SubscribeResponse } from "../types";
6
+ import { SubscribeBrokerLifecycle } from "./broker-lifecycle";
6
7
  export type SubscribeDeps = {
7
8
  brokers: Record<string, BrokerPoolEntry>;
8
9
  whitelistIps: string[];
9
10
  otelMetrics?: OtelMetrics;
10
11
  brokerArchiver?: BrokerExecutionArchiver;
12
+ brokerLifecycle?: SubscribeBrokerLifecycle;
11
13
  };
12
14
  type SubscribeCall = grpc.ServerWritableStream<SubscribeRequest, SubscribeResponse>;
13
15
  export declare function createSubscribeHandler(deps: SubscribeDeps): (call: SubscribeCall) => Promise<void>;
@@ -1 +1,2 @@
1
+ export { SubscribeBrokerLifecycle } from "./broker-lifecycle";
1
2
  export { createSubscribeHandler, type SubscribeDeps } from "./handler";
package/dist/index.js CHANGED
@@ -295372,6 +295372,59 @@ function createExecuteActionHandler(deps) {
295372
295372
  }
295373
295373
  };
295374
295374
  }
295375
+ // src/handlers/subscribe/broker-lifecycle.ts
295376
+ class SubscribeBrokerLifecycle {
295377
+ #brokers = new Map;
295378
+ #closing = new Map;
295379
+ #shuttingDown = false;
295380
+ register(broker, context3) {
295381
+ this.#brokers.set(broker, context3);
295382
+ if (this.#shuttingDown) {
295383
+ this.close(broker);
295384
+ }
295385
+ }
295386
+ close(broker) {
295387
+ const existing = this.#closing.get(broker);
295388
+ if (existing) {
295389
+ return existing;
295390
+ }
295391
+ const context3 = this.#brokers.get(broker) ?? {
295392
+ cex: "unknown",
295393
+ symbol: "unknown"
295394
+ };
295395
+ this.#brokers.delete(broker);
295396
+ const closing = (async () => {
295397
+ try {
295398
+ await broker.close();
295399
+ log.debug("Request-scoped Subscribe broker closed", context3);
295400
+ return "closed";
295401
+ } catch (error48) {
295402
+ log.warn("Failed to close request-scoped Subscribe broker", {
295403
+ ...context3,
295404
+ error: error48
295405
+ });
295406
+ return "failed";
295407
+ } finally {
295408
+ this.#closing.delete(broker);
295409
+ }
295410
+ })();
295411
+ this.#closing.set(broker, closing);
295412
+ return closing;
295413
+ }
295414
+ async closeAll() {
295415
+ this.#shuttingDown = true;
295416
+ let failed = 0;
295417
+ while (this.#brokers.size > 0 || this.#closing.size > 0) {
295418
+ const inFlight = [...this.#closing.values()];
295419
+ const fresh = [...this.#brokers.keys()].map((broker) => this.close(broker));
295420
+ const outcomes = await Promise.all([...fresh, ...inFlight]);
295421
+ failed += outcomes.filter((outcome) => outcome === "failed").length;
295422
+ }
295423
+ if (failed > 0) {
295424
+ throw new Error(`${failed} request-scoped Subscribe broker(s) failed to close`);
295425
+ }
295426
+ }
295427
+ }
295375
295428
  // src/handlers/subscribe/handler.ts
295376
295429
  import * as grpc13 from "@grpc/grpc-js";
295377
295430
 
@@ -296449,15 +296502,34 @@ async function runCcxtSubscribeLoop(call, isClosed, symbol2, subscriptionType, w
296449
296502
  }
296450
296503
  function createSubscribeHandler(deps) {
296451
296504
  const { brokers, whitelistIps, otelMetrics, brokerArchiver } = deps;
296505
+ const brokerLifecycle = deps.brokerLifecycle ?? new SubscribeBrokerLifecycle;
296452
296506
  return async (call) => {
296453
296507
  const subscribeStartTime = Date.now();
296454
296508
  let streamClosed = false;
296509
+ let ownedBroker = null;
296510
+ let ownedBrokerClosePromise;
296455
296511
  const markStreamClosed = () => {
296456
296512
  streamClosed = true;
296457
296513
  };
296458
- const isStreamClosed = () => streamClosed || call.destroyed;
296459
- call.once("close", markStreamClosed);
296514
+ const isStreamClosed = () => streamClosed || call.cancelled || call.writableEnded;
296515
+ const closeOwnedBroker = () => {
296516
+ if (ownedBrokerClosePromise) {
296517
+ return ownedBrokerClosePromise;
296518
+ }
296519
+ if (!ownedBroker) {
296520
+ return Promise.resolve();
296521
+ }
296522
+ const broker = ownedBroker;
296523
+ ownedBroker = null;
296524
+ ownedBrokerClosePromise = brokerLifecycle.close(broker);
296525
+ return ownedBrokerClosePromise;
296526
+ };
296527
+ const closeOwnedBrokerOnCallEnd = () => {
296528
+ closeOwnedBroker();
296529
+ };
296460
296530
  call.once("cancelled", markStreamClosed);
296531
+ call.once("cancelled", closeOwnedBrokerOnCallEnd);
296532
+ call.once("error", closeOwnedBrokerOnCallEnd);
296461
296533
  call.once("end", () => {
296462
296534
  markStreamClosed();
296463
296535
  log.info("Subscribe stream ended");
@@ -296529,6 +296601,17 @@ function createSubscribeHandler(deps) {
296529
296601
  });
296530
296602
  return;
296531
296603
  }
296604
+ if (!selectedBrokerAccount) {
296605
+ ownedBroker = broker;
296606
+ brokerLifecycle.register(broker, {
296607
+ cex: normalizedCex,
296608
+ symbol: symbol2
296609
+ });
296610
+ if (isStreamClosed()) {
296611
+ await closeOwnedBroker();
296612
+ return;
296613
+ }
296614
+ }
296532
296615
  const resolvedSymbol = await resolveSubscriptionSymbol(broker, symbol2, options?.marketType);
296533
296616
  const assetType = parseMarketType(options?.marketType);
296534
296617
  const deploymentId = brokerArchiver?.getDeploymentId() ?? "unknown";
@@ -296793,6 +296876,10 @@ function createSubscribeHandler(deps) {
296793
296876
  symbol: "",
296794
296877
  type: subscriptionType
296795
296878
  });
296879
+ } finally {
296880
+ call.off("cancelled", closeOwnedBrokerOnCallEnd);
296881
+ call.off("error", closeOwnedBrokerOnCallEnd);
296882
+ await closeOwnedBroker();
296796
296883
  }
296797
296884
  };
296798
296885
  }
@@ -296943,7 +297030,7 @@ var CEX_BROKER_PACKAGE_DEFINITION = protoLoader.fromJSON(node_descriptor_default
296943
297030
  // src/server.ts
296944
297031
  var grpcObj = grpc14.loadPackageDefinition(CEX_BROKER_PACKAGE_DEFINITION);
296945
297032
  var cexNode = grpcObj.cex_broker;
296946
- function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, otelMetrics, brokerArchiver, orderActivityTracker, withdrawalObservationTracker) {
297033
+ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, otelMetrics, brokerArchiver, orderActivityTracker, withdrawalObservationTracker, subscribeBrokerLifecycle) {
296947
297034
  const server = new grpc14.Server;
296948
297035
  server.addService(cexNode.cex_service.service, {
296949
297036
  ExecuteAction: createExecuteActionHandler({
@@ -296961,7 +297048,8 @@ function getServer(policy, brokers, whitelistIps, useVerity, verityProverUrl, ot
296961
297048
  brokers,
296962
297049
  whitelistIps,
296963
297050
  otelMetrics,
296964
- brokerArchiver
297051
+ brokerArchiver,
297052
+ brokerLifecycle: subscribeBrokerLifecycle
296965
297053
  })
296966
297054
  });
296967
297055
  return server;
@@ -297324,4 +297412,4 @@ export {
297324
297412
  CEXBroker as default
297325
297413
  };
297326
297414
 
297327
- //# debugId=186957481DC5AB2064756E2164756E21
297415
+ //# debugId=1D08CFF8FA968C4064756E2164756E21