internal void unsubscribe(string subject, string ackInbox) { IConnection lnc; lock (mu) { lnc = this.nc; subMap.Remove(ackInbox); } UnsubscribeRequest usr = new UnsubscribeRequest(); usr.ClientID = clientID; usr.Subject = subject; usr.Inbox = ackInbox; byte[] b = ProtocolSerializer.marshal(usr); var r = lnc.Request(unsubRequests, b, 2000); SubscriptionResponse sr = new SubscriptionResponse(); ProtocolSerializer.unmarshal(r.Data, sr); if (!string.IsNullOrEmpty(sr.Error)) { throw new StanException(sr.Error); } }
public void Close() { Msg reply = null; lock (mu) { cleanupOnClose(null); if (nc == null || nc.IsClosed()) { nc = null; return; } CloseRequest req = new CloseRequest { ClientID = clientID }; try { if (closeRequests != null) { reply = nc.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) { nc.Close(); } nc = null; } }
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 { ClientID = clientID, Subject = subject, 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); } }
internal Connection(string stanClusterID, string clientID, StanOptions options) { this.clientID = clientID; connID = Google.Protobuf.ByteString.CopyFrom(System.Text.Encoding.UTF8.GetBytes(pubNUID.Next)); opts = (options != null) ? new StanOptions(options) : new StanOptions(); if (opts.natsConn == null) { ncOwned = true; try { nc = new ConnectionFactory().CreateConnection(opts.NatsURL); nc.Opts.MaxReconnect = Options.ReconnectForever; // TODO: disable buffering. } catch (Exception ex) { throw new StanConnectionException(ex); } } else { nc = opts.natsConn; ncOwned = false; } // Prepare a subscription on ping responses, even if we are not // going to need it, so that if that fails, it fails before initiating // a connection. pingSubscription = nc.SubscribeAsync(newInbox(), processPingResponse); // create a heartbeat inbox string hbInbox = newInbox(); hbSubscription = nc.SubscribeAsync(hbInbox, processHeartBeat); string discoverSubject = opts.discoverPrefix + "." + stanClusterID; // The streaming server expects seconds, but can handle millis // millis are denoted by negative numbers. int pi; if (opts.PingInterval < 1000) { pi = opts.pingInterval * -1; } else { pi = opts.pingInterval / 1000; } ConnectRequest req = new ConnectRequest { ClientID = clientID, HeartbeatInbox = hbInbox, ConnID = (Google.Protobuf.ByteString)connID, Protocol = StanConsts.protocolOne, PingMaxOut = opts.PingMaxOutstanding, PingInterval = pi }; Msg cr; try { cr = nc.Request(discoverSubject, ProtocolSerializer.marshal(req), opts.ConnectTimeout); } catch (NATSTimeoutException) { protoUnsubscribe(); throw new StanConnectRequestTimeoutException( string.Format("No response from a streaming server with a cluster ID of '{0}'", stanClusterID)); } ConnectResponse response = new ConnectResponse(); try { ProtocolSerializer.unmarshal(cr.Data, response); } catch (Exception e) { protoUnsubscribe(); throw new StanConnectRequestException(e); } if (!string.IsNullOrEmpty(response.Error)) { protoUnsubscribe(); 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); // TODO - check out sub map and chans bool unsubPing = true; // Do this with servers which are at least at protcolOne. if (response.Protocol >= StanConsts.protocolOne) { // Note that in the future server may override client ping // interval value sent in ConnectRequest, so use the // value in ConnectResponse to decide if we send PINGs // and at what interval. // In tests, the interval could be negative to indicate // milliseconds. if (response.PingInterval != 0) { unsubPing = false; // These will be immutable pingRequests = response.PingRequests; pingInbox = pingSubscription.Subject; // negative values returned from the server are ms if (response.PingInterval < 0) { pingInterval = response.PingInterval * -1; } else { // if positive, the result is in seconds, but // in the .NET clients we always use millis. pingInterval = response.PingInterval * 1000; } pingMaxOut = response.PingMaxOut; pingBytes = ProtocolSerializer.createPing(connID); pingTimer = new Timer(pingServer, null, pingInterval, Timeout.Infinite); } } if (unsubPing) { pingSubscription.Unsubscribe(); pingSubscription = null; } }
// 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); Msg m = sc.NATSConnection.Request(subRequestSubject, b, sc.opts.ConnectTimeout); 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; } 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); }
public void Close() { Msg reply = null; lock (mu) { cleanupOnClose(null); if (nc == null || nc.IsClosed()) { nc = null; return; } CloseRequest req = new CloseRequest { ClientID = clientID }; try { if (closeRequests != null) { reply = nc.Request(closeRequests, ProtocolSerializer.marshal(req)); } } catch (StanBadSubscriptionException) { // it's possible we never actually connected. return; } catch (NATSReconnectBufferException) { // In order to maintain backward compatibility, we need to avoid throwing // this exception. The reply will be null, so we'll fall through // and gracefully close the streaming connection. The streaming server // will cleanup this client on its own. } 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) { nc.Close(); } nc = null; } }