internal void processMsg(object sender, MsgHandlerEventArgs args) { bool isClosed = false; AsyncSubscription sub = null; Msg raw = null; MsgProto mp = new MsgProto(); ProtocolSerializer.unmarshal(args.Message.Data, mp); raw = args.Message; lock (mu) { isClosed = (nc == null); subMap.TryGetValue(raw.Subject, out sub); } if (isClosed || sub == null) { return; } sub.processMsg(mp); }
internal void unsubscribe(string subject, string inbox, string ackInbox, bool close) { IConnection lnc; lock (mu) { lnc = nc; if (lnc == null) { throw new StanConnectionClosedException(); } subMap.Remove(inbox); } string requestSubject = unsubRequests; if (close) { requestSubject = subCloseRequests; if (string.IsNullOrEmpty(requestSubject)) { throw new StanNoServerSupport(); } } UnsubscribeRequest usr = new UnsubscribeRequest(); usr.ClientID = clientID; usr.Subject = subject; usr.Inbox = ackInbox; byte[] b = ProtocolSerializer.marshal(usr); var r = lnc.Request(requestSubject, b, 2000); SubscriptionResponse sr = new SubscriptionResponse(); ProtocolSerializer.unmarshal(r.Data, sr); if (!string.IsNullOrEmpty(sr.Error)) { throw new StanException(sr.Error); } }
private void processAck(object sender, MsgHandlerEventArgs args) { PubAck pa = new PubAck(); try { ProtocolSerializer.unmarshal(args.Message.Data, pa); } catch (Exception) { // TODO: (cls) handle this... return; } PublishAck a = removeAck(pa.Guid); if (a != null) { a.invokeHandler(pa.Guid, pa.Error); } }
// in STAN, much of this code is in the connection module. internal void subscribe(string subRequestSubject, string subject, string qgroup, EventHandler <StanMsgHandlerArgs> handler) { rwLock.EnterWriteLock(); try { this.handler += handler; this.subject = subject; if (sc == null) { throw new StanConnectionClosedException(); } // Listen for actual messages. inboxSub = sc.NATSConnection.SubscribeAsync(inbox, sc.processMsg); SubscriptionRequest sr = new SubscriptionRequest(); sr.ClientID = sc.ClientID; sr.Subject = subject; sr.QGroup = (qgroup == null ? "" : qgroup); sr.Inbox = inbox; sr.MaxInFlight = options.MaxInflight; sr.AckWaitInSecs = options.AckWait / 1000; sr.StartPosition = options.startAt; sr.DurableName = (options.DurableName == null ? "" : options.DurableName); // Conditionals switch (sr.StartPosition) { case StartPosition.TimeDeltaStart: sr.StartTimeDelta = convertTimeSpan( options.useStartTimeDelta ? options.startTimeDelta : (DateTime.UtcNow - options.startTime)); break; case StartPosition.SequenceStart: sr.StartSequence = options.startSequence; break; } byte[] b = ProtocolSerializer.marshal(sr); // TODO: Configure request timeout? Msg m = sc.NATSConnection.Request(subRequestSubject, b, 2000); SubscriptionResponse r = new SubscriptionResponse(); ProtocolSerializer.unmarshal(m.Data, r); if (string.IsNullOrWhiteSpace(r.Error) == false) { throw new StanException(r.Error); } ackInbox = r.AckInbox; } catch { if (inboxSub != null) { try { inboxSub.Unsubscribe(); } catch (NATSTimeoutException) { // NOOP - this is unrecoverable. } } throw; } finally { rwLock.ExitWriteLock(); } }
public void Close() { Msg reply = null; lock (mu) { IConnection lnc = nc; nc = null; if (lnc == null) { return; } if (lnc.IsClosed()) { return; } if (ackSubscription != null) { ackSubscription.Unsubscribe(); ackSubscription = null; } if (hbSubscription != null) { hbSubscription.Unsubscribe(); hbSubscription = null; } if (heartbeatMonitor != null) { heartbeatMonitor.Stop(); } CloseRequest req = new CloseRequest(); req.ClientID = this.clientID; try { if (this.closeRequests != null) { reply = lnc.Request(closeRequests, ProtocolSerializer.marshal(req)); } } catch (StanBadSubscriptionException) { // it's possible we never actually connected. return; } if (reply != null) { CloseResponse resp = new CloseResponse(); try { ProtocolSerializer.unmarshal(reply.Data, resp); } catch (Exception e) { throw new StanCloseRequestException(e); } if (!string.IsNullOrEmpty(resp.Error)) { throw new StanCloseRequestException(resp.Error); } } if (ncOwned && lnc != null) { lnc.Close(); } } }
internal Connection(string stanClusterID, string clientID, StanOptions options) { this.clientID = clientID; if (options != null) { opts = new StanOptions(options); } else { opts = new StanOptions(); } if (opts.natsConn == null) { ncOwned = true; try { nc = new ConnectionFactory().CreateConnection(opts.NatsURL); } catch (Exception ex) { throw new StanConnectionException(ex); } } else { nc = opts.natsConn; ncOwned = false; } // create a heartbeat inbox string hbInbox = newInbox(); hbSubscription = nc.SubscribeAsync(hbInbox, processHeartBeat); string discoverSubject = opts.discoverPrefix + "." + stanClusterID; ConnectRequest req = new ConnectRequest(); req.ClientID = this.clientID; req.HeartbeatInbox = hbInbox; Msg cr; try { cr = nc.Request(discoverSubject, ProtocolSerializer.marshal(req), opts.ConnectTimeout); } catch (NATSTimeoutException) { throw new StanConnectRequestTimeoutException(); } ConnectResponse response = new ConnectResponse(); try { ProtocolSerializer.unmarshal(cr.Data, response); } catch (Exception e) { throw new StanConnectRequestException(e); } if (!string.IsNullOrEmpty(response.Error)) { throw new StanConnectRequestException(response.Error); } // capture cluster configuration endpoints to publish and subscribe/unsubscribe pubPrefix = response.PubPrefix; subRequests = response.SubRequests; unsubRequests = response.UnsubRequests; subCloseRequests = response.SubCloseRequests; closeRequests = response.CloseRequests; // setup the Ack subscription ackSubject = StanConsts.DefaultACKPrefix + "." + newGUID(); ackSubscription = nc.SubscribeAsync(ackSubject, processAck); // TODO: hardcode or options? ackSubscription.SetPendingLimits(1024 * 1024, 32 * 1024 * 1024); pubAckMap = new BlockingDictionary <string, PublishAck>(opts.maxPubAcksInflight); // Setup server heartbeat monitor if (options != null && options.ServerHeartbeatTimeoutMillis > 0) { heartbeatMonitor = new ServerHeartbeatMonitor(1000, options.ServerHeartbeatTimeoutMillis, () => { options.ServerHeartbeatTimeoutCallback?.Invoke(); }); heartbeatMonitor.Start(); } }