public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Push Subscribe Basic Async", args, Usage) .DefaultStream("example-stream") .DefaultSubject("example-subject") .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { JsUtils.CreateStreamWhenDoesNotExist(c, helper.Stream, helper.Subject); IJetStream js = c.CreateJetStreamContext(); new Thread(() => { js.PushSubscribeAsync(helper.Subject, (sender, a) => { a.Message.Ack(); Console.WriteLine(Encoding.UTF8.GetString(a.Message.Data)); }, false); }).Start(); Thread.Sleep(3000); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Expires In", args, Usage) .DefaultStream("fetch-stream") .DefaultSubject("fetch-subject") .DefaultDurable("fetch-durable") .DefaultCount(15) .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Start publishing the messages, don't wait for them to finish, simulating an outside producer. JsUtils.PublishInBackground(js, helper.Subject, "fetch-message", helper.Count); // Build our consumer configuration and subscription options. // make sure the ack wait is sufficient to handle the reading and processing of the batch. // Durable is REQUIRED for pull based subscriptions ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckWait(2500) .Build(); PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .WithConfiguration(cc) .Build(); // subscribe IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); int red = 0; while (red < helper.Count) { IList <Msg> list = sub.Fetch(10, 1000); foreach (Msg m in list) { Console.WriteLine($"{++red}. Message: {m}"); m.Ack(); } } // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish Vs Core Publish", args, Usage) .DefaultStream("js-or-core-stream") .DefaultSubject("js-or-core-subject") .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // create a JetStream context IJetStream js = c.CreateJetStreamContext(); // Regular Nats publish is straightforward c.Publish(helper.Subject, Encoding.ASCII.GetBytes("regular-message")); // A JetStream publish allows you to set publish options // that a regular publish does not. // A JetStream publish returns an ack of the publish. There // is no ack in a regular message. Msg msg = new Msg(helper.Subject, Encoding.ASCII.GetBytes("js-message")); PublishAck pa = js.Publish(msg); Console.WriteLine(pa); // set up the subscription IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(helper.Subject); c.Flush(500); // flush outgoing communication with/to the server // Both messages appear in the stream as JetStream messages msg = sub.NextMessage(500); msg.Ack(); Console.WriteLine("Received Data: '" + Encoding.ASCII.GetString(msg.Data) + "'\n Meta: " + msg.MetaData); msg = sub.NextMessage(500); msg.Ack(); Console.WriteLine("Received Data: '" + Encoding.ASCII.GetString(msg.Data) + "'\n Meta: " + msg.MetaData); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish", args, Usage) .DefaultStream("example-stream") .DefaultSubject("example-subject") .DefaultPayload("Hello") .DefaultCount(10) .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Use the utility to create a stream stored in memory. JsUtils.CreateStreamOrUpdateSubjects(c, helper.Stream, helper.Subject); // create a JetStream context IJetStream js = c.CreateJetStreamContext(); int stop = helper.Count < 2 ? 2 : helper.Count + 1; for (int x = 1; x < stop; x++) { // make unique message data if you want more than 1 message byte[] data = helper.Count < 2 ? Encoding.UTF8.GetBytes(helper.Payload) : Encoding.UTF8.GetBytes(helper.Payload + "-" + x); // Publish a message and print the results of the publish acknowledgement. Msg msg = new Msg(helper.Subject, null, helper.Header, data); // We'll use the defaults for this simple example, but there are options // to constrain publishing to certain streams, expect sequence numbers and // more. See the JetStreamPublishWithOptionsUseCases example for details. // An exception will be thrown if there is a failure. PublishAck pa = js.Publish(msg); Console.WriteLine("Published message '{0}' on subject '{1}', stream '{2}', seqno '{3}'.", Encoding.UTF8.GetString(data), helper.Subject, pa.Stream, pa.Seq); } } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("KeyValueFull", args, Usage) .DefaultBucket("exampleBucket") .DefaultDescription("Example Description") .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // get the kv management context IKeyValueManagement kvm = c.CreateKeyValueManagementContext(); // create the bucket KeyValueConfiguration kvc = KeyValueConfiguration.Builder() .WithName(helper.Bucket) .WithDescription(helper.Description) .WithMaxHistoryPerKey(5) .WithStorageType(StorageType.Memory) .Build(); KeyValueStatus kvs = kvm.Create(kvc); Console.WriteLine(kvs); // get the kv context for the specific bucket IKeyValue kv = c.CreateKeyValueContext(helper.Bucket); // Put some keys. Each key is put in a subject in the bucket (stream) // The put returns the revision number in the bucket (stream) Console.WriteLine("\n1. Put"); ulong seq = kv.Put(ByteKey, Encoding.UTF8.GetBytes("Byte Value 1")); Console.WriteLine("Revision number should be 1, got " + seq); seq = kv.Put(StringKey, "String Value 1"); Console.WriteLine("Revision number should be 2, got " + seq); seq = kv.Put(LongKey, 1); Console.WriteLine("Revision number should be 3, got " + seq); // retrieve the values. all types are stored as bytes // so you can always get the bytes directly Console.WriteLine("\n2. Get Value (Bytes)"); byte[] bvalue = kv.Get(ByteKey).Value; Console.WriteLine(ByteKey + " from Value property: " + Encoding.UTF8.GetString(bvalue)); bvalue = kv.Get(StringKey).Value; Console.WriteLine(StringKey + " from Value property: " + Encoding.UTF8.GetString(bvalue)); bvalue = kv.Get(LongKey).Value; Console.WriteLine(LongKey + " from Value property: " + Encoding.UTF8.GetString(bvalue)); // if you know the value is not binary and can safely be read // as a UTF-8 string, the ValueAsString function is ok to use Console.WriteLine("\n3. Get String Value"); String svalue = kv.Get(ByteKey).ValueAsString(); Console.WriteLine(ByteKey + " from ValueAsString(): " + svalue); svalue = kv.Get(StringKey).ValueAsString(); Console.WriteLine(StringKey + " from ValueAsString(): " + svalue); svalue = kv.Get(LongKey).ValueAsString(); Console.WriteLine(LongKey + " from ValueAsString(): " + svalue); // if you know the value is a long, you can use // the getLongValue method // if it's not a number a NumberFormatException is thrown Console.WriteLine("\n4. Get Long Value"); long lvalue; bool bLongGet = kv.Get(LongKey).TryGetLongValue(out lvalue); Console.WriteLine(LongKey + " from getValueAsLong: " + lvalue); bLongGet = kv.Get(StringKey).TryGetLongValue(out lvalue); if (!bLongGet) { Console.WriteLine(StringKey + " value is not a long!"); } // entry gives detail about latest record of the key Console.WriteLine("\n5. Get Entry"); KeyValueEntry entry = kv.Get(ByteKey); Console.WriteLine(ByteKey + " entry: " + entry); entry = kv.Get(StringKey); Console.WriteLine(StringKey + " entry: " + entry); entry = kv.Get(LongKey); Console.WriteLine(LongKey + " entry: " + entry); // delete a key Console.WriteLine("\n6. Delete a key"); kv.Delete(ByteKey); // it's value is now null // it's value is now null but there is a delete tombstone KeyValueEntry kve = kv.Get(ByteKey); Console.WriteLine("Delete tombstone entry: " + kve); Console.WriteLine("Revision number should be 4, got " + kve.Revision); Console.WriteLine("Deleted value should be null: " + (kve.Value == null)); // if the key does not exist there is no entry at all Console.WriteLine("\n7.1 Keys does not exist"); kve = kv.Get(NotFound); Console.WriteLine($"Entry for {NotFound} should be null: {kve == null}"); // if the key has been deleted there is an entry for it // but the value will be null Console.WriteLine("\n7.2 Keys not found"); bvalue = kv.Get(ByteKey).Value; Console.WriteLine($"{ByteKey} byte value should be null: {bvalue == null}"); svalue = kv.Get(ByteKey).ValueAsString(); Console.WriteLine($"{ByteKey} string value should be null: " + (svalue == null)); bLongGet = kv.Get(ByteKey).TryGetLongValue(out lvalue); if (!bLongGet) { Console.WriteLine(ByteKey + " value is not a long!"); } // Update values. You can even update a deleted key Console.WriteLine("\n8.1 Update values"); seq = kv.Put(ByteKey, Encoding.UTF8.GetBytes("Byte Value 2")); Console.WriteLine("Revision number should be 5, got " + seq); seq = kv.Put(StringKey, "String Value 2"); Console.WriteLine("Revision number should be 6, got " + seq); seq = kv.Put(LongKey, 2); Console.WriteLine("Revision number should be 7, got " + seq); // values after updates Console.WriteLine("\n8.2 Values after update"); svalue = kv.Get(ByteKey).ValueAsString(); Console.WriteLine(ByteKey + " from ValueAsString(): " + svalue); svalue = kv.Get(StringKey).ValueAsString(); Console.WriteLine(StringKey + " from ValueAsString(): " + svalue); bLongGet = kv.Get(LongKey).TryGetLongValue(out lvalue); Console.WriteLine(LongKey + " from TryGetLongValue: " + lvalue); // let's check the bucket info Console.WriteLine("\n9.1 Bucket before update/delete"); kvs = kvm.GetBucketInfo(helper.Bucket); Console.WriteLine(kvs); kvc = KeyValueConfiguration.Builder(kvs.Config) .WithDescription(helper.Description + "-changed") .WithMaxHistoryPerKey(6) .Build(); kvs = kvm.Update(kvc); Console.WriteLine("\n9.2 Bucket after update"); Console.WriteLine(kvs); // delete the bucket Console.WriteLine("\n9.3 Delete"); kvm.Delete(helper.Bucket); try { kvm.GetBucketInfo(helper.Bucket); Console.WriteLine("UH OH! Bucket should not have been found!"); } catch (NATSJetStreamException) { Console.WriteLine("Bucket was not found!"); } } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Expires In", args, Usage) .DefaultStream("fetch-uc-stream") .DefaultSubject("fetch-uc-subject") .DefaultDurable("fetch-uc-durable") .DefaultCount(15) .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our consumer configuration and subscription options. // make sure the ack wait is sufficient to handle the reading and processing of the batch. // Durable is REQUIRED for pull based subscriptions ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckWait(2500) .Build(); PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .WithConfiguration(cc) .Build(); // 0.1 Initialize. subscription // 0.2 Flush outgoing communication with/to the server, useful when app is both JsUtils.Publishing and subscribing. Console.WriteLine("\n----------\n0. Initialize the subscription and pull."); IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); // 1. Fetch, but there are no messages yet. // - Read the messages, get them all (0) Console.WriteLine("----------\n1. There are no messages yet"); IList <Msg> messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); // 2. Publish 10 messages // - Fetch messages, get 10 Console.WriteLine("----------\n2. Publish 10 which satisfies the batch"); JsUtils.Publish(js, helper.Subject, "A", 10); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 3. Publish 20 messages // - Fetch messages, only get 10 Console.WriteLine("----------\n3. Publish 20 which is larger than the batch size."); JsUtils.Publish(js, helper.Subject, "B", 20); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 4. There are still messages left from the last // - Fetch messages, get 10 Console.WriteLine("----------\n4. Get the rest of the JsUtils.Publish."); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 5. Publish 5 messages // - Fetch messages, get 5 // - Since there are less than batch size we only get what the server has. Console.WriteLine("----------\n5. Publish 5 which is less than batch size."); JsUtils.Publish(js, helper.Subject, "C", 5); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 5 total messages, we received: " + messages.Count); // 6. Publish 15 messages // - Fetch messages, only get 10 Console.WriteLine("----------\n6. Publish 15 which is more than the batch size."); JsUtils.Publish(js, helper.Subject, "D", 15); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 7. There are 5 messages left // - Fetch messages, only get 5 Console.WriteLine("----------\n7. There are 5 messages left."); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 5 messages, we received: " + messages.Count); // 8. Read but don't ack. // - Fetch messages, get 10, but either take too long to ack them or don't ack them Console.WriteLine("----------\n8. Fetch but don't ack."); JsUtils.Publish(js, helper.Subject, "E", 10); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); Console.WriteLine("We should have received 10 message, we received: " + messages.Count); Thread.Sleep(3000); // longer than the ackWait // 9. Fetch messages, // - get the 10 messages we didn't ack Console.WriteLine("----------\n9. Fetch, get the messages we did not ack."); messages = sub.Fetch(10, 3000); JsUtils.Report(messages); foreach (Msg m in messages) { m.Ack(); } Console.WriteLine("We should have received 10 message, we received: " + messages.Count); Console.WriteLine("----------\n"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("NATS JetStream Push Subscribe Bind Durable", args, Usage) .DefaultStream("fs-stream") .DefaultSubject("fs-subject") .Build(); string subjectWild = helper.Subject + ".*"; string subjectA = helper.Subject + ".A"; string subjectB = helper.Subject + ".B"; try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, subjectWild); // Create our JetStream context to publish and receive JetStream messages. IJetStream js = c.CreateJetStreamContext(); JsUtils.Publish(js, subjectA, 1); JsUtils.Publish(js, subjectB, 1); JsUtils.Publish(js, subjectA, 1); JsUtils.Publish(js, subjectB, 1); // 1. create a subscription that subscribes to the wildcard subject ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) // don't want to worry about acking messages. .Build(); PushSubscribeOptions pso = PushSubscribeOptions.Builder() .WithConfiguration(cc) .Build(); IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(5000); Msg m = sub.NextMessage(1000); Console.WriteLine("\n1A1. Message should be from '" + subjectA + "', Sequence #1. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("1B2. Message should be from '" + subjectB + "', Sequence #2. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("1A3. Message should be from '" + subjectA + "', Sequence #3. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("1B4. Message should be from '" + subjectB + "', Sequence #4. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); // 2. create a subscription that subscribes only to the A subject cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) // don't want to worry about acking messages. .WithFilterSubject(subjectA) .Build(); pso = PushSubscribeOptions.Builder() .WithConfiguration(cc) .Build(); sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(5000); m = sub.NextMessage(1000); Console.WriteLine("\n2A1. Message should be from '" + subjectA + "', Sequence #1. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("2A3. Message should be from '" + subjectA + "', Sequence #3. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); try { sub.NextMessage(1000); Console.WriteLine("2x. NOPE! Should not have gotten here"); } catch (NATSTimeoutException) // timeout means there are no messages available { Console.WriteLine("2x. There was no message available."); } // 3. create a subscription that subscribes only to the A subject cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) // don't want to worry about acking messages. .WithFilterSubject(subjectB) .Build(); pso = PushSubscribeOptions.Builder() .WithConfiguration(cc) .Build(); sub = js.PushSubscribeSync(subjectWild, pso); c.Flush(5000); m = sub.NextMessage(1000); Console.WriteLine("\n3A2. Message should be from '" + subjectB + "', Sequence #2. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); m = sub.NextMessage(1000); Console.WriteLine("3A4. Message should be from '" + subjectB + "', Sequence #4. " + "It was: '" + m.Subject + "', Seq #" + m.MetaData.StreamSequence); try { sub.NextMessage(1000); Console.WriteLine("3x. NOPE! Should not have gotten here"); } catch (NATSTimeoutException) // timeout means there are no messages available { Console.WriteLine("3x. There was no message available."); } Console.WriteLine(); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Expires In, Use Cases", args, Usage) .DefaultStream("expires-in-uc-stream") .DefaultSubject("expires-in-uc-subject") .DefaultDurable("expires-in-uc-durable") .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .Build(); // 0.1 Initialize. subscription // 0.2 Flush outgoing communication with/to the server, useful when app is both JsUtils.Publishing and subscribing. // 0.3 Start the pull, you don't have to call this again because AckMode.NEXT // - When we ack a batch message the server starts preparing or adding to the next batch. Console.WriteLine("\n----------\n0. Initialize the subscription and pull."); IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); // 1. Publish some that is less than the batch size. Console.WriteLine("\n----------\n1. Publish some amount of messages, but not entire batch size."); JsUtils.Publish(js, helper.Subject, "A", 6); sub.PullExpiresIn(10, 1200); IList <Msg> messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 6 total messages, we received: " + messages.Count); // 2. Publish some more covering our pull size... Console.WriteLine("----------\n2. Publish more than the batch size."); sub.PullExpiresIn(10, 1200); JsUtils.Publish(js, helper.Subject, "B", 14); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 3. There are still 4 messages from B, but the batch was finished // - won't get any messages until a pull is issued. Console.WriteLine("----------\n3. Read without issuing a pull."); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); // 4. re-issue the pull to get the last 4 Console.WriteLine("----------\n4. Issue the pull to get the last 4."); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 4 total messages, we received: " + messages.Count); // 5. publish a lot of messages Console.WriteLine("----------\n5. Publish a lot of messages. The last pull was under the batch size."); Console.WriteLine(" Issue another pull with batch size less than number of messages."); JsUtils.Publish(js, helper.Subject, "C", 25); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 6. there are still more messages Console.WriteLine("----------\n6. Still more messages. Issue another pull with batch size less than number of messages."); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 7. there are still more messages Console.WriteLine("----------\n7. Still more messages. Issue another pull with batch size more than number of messages."); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 5 total messages, we received: " + messages.Count); // 8. we got them all Console.WriteLine("----------\n8. No messages left."); sub.PullExpiresIn(10, 1200); messages = JsUtils.ReadMessagesAck(sub, timeout: 2000); Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); Console.WriteLine("----------\n"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("NATS JetStream Push Subscribe Bind Durable", args, Usage) .DefaultStream("fs-stream") .DefaultSubject("fs-subject") .Build(); string subjectNoAck = helper.Subject + "noack"; string subjectAck = helper.Subject + "ack"; string deliverNoAck = helper.DeliverSubject + "noack"; string deliverAck = helper.DeliverSubject + "ack"; try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, subjectNoAck, subjectAck); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // The server uses the delivery subject as both an inbox for a JetStream subscription // and as a core nats messages subject. // BUT BE CAREFUL. THIS IS STILL A JETSTREAM SUBJECT AND ALL MESSAGES // ADHERE TO THE ACK POLICY // NoAck 1. Set up the noAck consumer / deliver subject configuration ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.None) .WithAckWait(1000) .Build(); PushSubscribeOptions pso = PushSubscribeOptions.Builder() .WithDeliverSubject(deliverNoAck) .WithConfiguration(cc) .Build(); // NoAck 2. Set up the JetStream and core subscriptions // Notice the JetStream subscribes to the real subject // and the core subscribes to the delivery subject // Order matters, you must do the JetStream subscribe first // But you also must make sure the core sub is made // before messages are published IJetStreamPushSyncSubscription jsSub = js.PushSubscribeSync(subjectNoAck, pso); c.Flush(5000); ISyncSubscription coreSub = c.SubscribeSync(deliverNoAck); // NoAck 3. JsUtils.Publish to the real subject JsUtils.Publish(js, subjectNoAck, "A", 1); // NoAck 4. Read the message with the js no ack subscription. No need to ack Msg msg = jsSub.NextMessage(1000); PrintMessage("\nNoAck 4. Read w/JetStream sub", msg); // NoAck 5. Read the message with the core subscription on the // no ack deliver subject. Since this message is a JetStream // message we could ack. But we don't have to since the consumer // was setup as AckPolicy None msg = coreSub.NextMessage(1000); PrintMessage("NoAck 5. Read w/core sub", msg); // NoAck 6. Thread.Sleep longer than the ack wait period to check and make sure the // message is not replayed Thread.Sleep(1100); try { coreSub.NextMessage(1000); Console.WriteLine("NoAck 6. NOPE! Should not have gotten here"); } catch (NATSTimeoutException) // timeout means there are no messages available { Console.WriteLine("NoAck 6. Read w/core sub.\nAck Policy is none so no replay even though message was not Ack'd.\nThere was no message available."); } // Ack 1. Set up the Ack consumer / deliver subject configuration cc = ConsumerConfiguration.Builder() .WithAckPolicy(AckPolicy.Explicit) .WithAckWait(1000) .Build(); pso = PushSubscribeOptions.Builder() .WithDeliverSubject(deliverAck) .WithConfiguration(cc) .Build(); // Ack 2. Set up the JetStream and core subscriptions jsSub = js.PushSubscribeSync(subjectAck, pso); c.Flush(5000); coreSub = c.SubscribeSync(deliverAck); // Ack 3. JsUtils.Publish to the real subject JsUtils.Publish(js, subjectAck, "B", 1); // Ack 4. Read the message with the js no ack subscription. No need to ack msg = jsSub.NextMessage(1000); PrintMessage("\nAck 4. Read w/JetStream sub", msg); // Ack 5. Read the message with the core subscription on the // ack deliver subject. // Even though it is read on a core subscription // it still is a JetStream message. Don't ack this time msg = coreSub.NextMessage(1000); PrintMessage("Ack 5. Read w/core sub", msg); // Ack 6. Thread.Sleep longer than the ack wait period to check and // see that the message is re-delivered. Ack this time. Thread.Sleep(1100); msg = coreSub.NextMessage(1000); msg.Ack(); PrintMessage("Ack 6. Read w/core sub.\nWasn't Ack'd after step 'Ack 5.' so message was replayed.", msg); // Ack 7. Thread.Sleep longer than the ack wait period. The message // is not re-delivered this time Thread.Sleep(1100); try { coreSub.NextMessage(1000); Console.WriteLine("Ack 7. NOPE! Should not have gotten here"); } catch (NATSTimeoutException) // timeout means there are no messages available { Console.WriteLine("Ack 7. Read w/core sub.\nMessage received by core sub in step 'Ack 6.' was JetStream so it was Ack'd and therefore not replayed.\nThere was no message available.", msg); } // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Manage Streams", args, Usage) .DefaultStream("manage-stream-") .DefaultSubject("manage-subject-") .Build(); string stream1 = helper.Stream + "1"; string stream2 = helper.Stream + "2"; string subject1 = helper.Subject + "1"; string subject2 = helper.Subject + "2"; string subject3 = helper.Subject + "3"; string subject4 = helper.Subject + "4"; try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // we want to be able to completely create and delete the streams // so don't want to work with existing streams JsUtils.ExitIfStreamExists(jsm, stream1); JsUtils.ExitIfStreamExists(jsm, stream2); // 1. Create (add) a stream with a subject Console.WriteLine("\n----------\n1. Configure And Add Stream 1"); StreamConfiguration streamConfig = StreamConfiguration.Builder() .WithName(stream1) .WithSubjects(subject1) // .WithRetentionPolicy(...) // .WithMaxConsumers(...) // .WithMaxBytes(...) // .WithMaxAge(...) // .WithMaxMsgSize(...) .WithStorageType(StorageType.Memory) // .WithReplicas(...) // .WithNoAck(...) // .WithTemplateOwner(...) // .WithDiscardPolicy(...) .Build(); StreamInfo streamInfo = jsm.AddStream(streamConfig); PrintUtils.PrintStreamInfo(streamInfo); // 2. Update stream, in this case add a subject // Thre are very few properties that can actually // - StreamConfiguration is immutable once created // - but the builder can help with that. Console.WriteLine("----------\n2. Update Stream 1"); streamConfig = StreamConfiguration.Builder(streamInfo.Config) .AddSubjects(subject2).Build(); streamInfo = jsm.UpdateStream(streamConfig); PrintUtils.PrintStreamInfo(streamInfo); // 3. Create (add) another stream with 2 subjects Console.WriteLine("----------\n3. Configure And Add Stream 2"); streamConfig = StreamConfiguration.Builder() .WithName(stream2) .WithSubjects(subject3, subject4) .WithStorageType(StorageType.Memory) .Build(); streamInfo = jsm.AddStream(streamConfig); PrintUtils.PrintStreamInfo(streamInfo); // 4. Get information on streams // 4.0 publish some message for more interesting stream state information // - SUBJECT1 is associated with STREAM1 // 4.1 getStreamInfo on a specific stream // 4.2 get a list of all streams // 4.3 get a list of StreamInfo's for all streams Console.WriteLine("----------\n4.1 getStreamInfo"); JsUtils.Publish(c, subject1, 5); streamInfo = jsm.GetStreamInfo(stream1); PrintUtils.PrintStreamInfo(streamInfo); Console.WriteLine("----------\n4.2 getStreamNames"); IList <String> streamNames = jsm.GetStreamNames(); PrintUtils.PrintObject(streamNames); Console.WriteLine("----------\n4.3 getStreams"); IList <StreamInfo> streamInfos = jsm.GetStreams(); PrintUtils.PrintStreamInfoList(streamInfos); // 5. Purge a stream of it's messages Console.WriteLine("----------\n5. Purge stream"); PurgeResponse purgeResponse = jsm.PurgeStream(stream1); PrintUtils.PrintObject(purgeResponse); // 6. Delete the streams // Subsequent calls to getStreamInfo, deleteStream or purgeStream // will throw a JetStreamApiException "stream not found [10059]" Console.WriteLine("----------\n6. Delete streams"); jsm.DeleteStream(stream1); jsm.DeleteStream(stream2); // 7. Try to delete the consumer again and get the exception Console.WriteLine("----------\n7. Delete stream again"); try { jsm.DeleteStream(stream1); } catch (NATSJetStreamException e) { Console.WriteLine($"Exception was: '{e.ErrorDescription}'"); } Console.WriteLine("----------\n"); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("NATS JetStream Push Subscribe Bind Durable", args, Usage) .DefaultStream("example-stream") .DefaultSubject("example-subject") .DefaultDurable("bind-durable") .DefaultDeliverSubject("bind-deliver") .DefaultCount(0, true) // true indicated 0 means unlimited .Build(); int count = helper.Count < 1 ? int.MaxValue : helper.Count; try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // The stream (and data) must exist JsUtils.ExitIfStreamNotExists(c, helper.Stream); // The durable consumer must already exist. Usually it would be made in configuration // or via the NATS CLI but we are making it here. // Important: The consumer must have a deliver subject when made this way or it will be // understood to be a pull consumer by the server. // NOTE: If you ran this example already, the consumer will have been created // This is not a problem if it is exactly the same. Most ConsumerConfiguration // properties are not modifiable once created. ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithDurable(helper.Durable) .WithDeliverSubject(helper.DeliverSubject) .Build(); c.CreateJetStreamManagementContext().AddOrUpdateConsumer(helper.Stream, cc); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // bind subscribe to the stream - either variety will work // V1. Version designed specifically for this purpose. PushSubscribeOptions so = PushSubscribeOptions.BindTo(helper.Stream, helper.Durable); // V2. optional long form // PushSubscribeOptions so = PushSubscribeOptions.Builder() // .WithBind(true) // .WithStream(helper.Stream) // .WithDurable(helper.Durable) // .Build(); // Subscribe synchronously, then just wait for messages. IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(helper.Subject, so); c.Flush(5000); int red = 0; while (count > 0) { try { Msg msg = sub.NextMessage(1000); Console.WriteLine("\nMessage Received:"); if (msg.HasHeaders) { Console.WriteLine(" Headers:"); foreach (string key in msg.Header.Keys) { foreach (string value in msg.Header.GetValues(key)) { Console.WriteLine($" {key}: {value}"); } } } Console.WriteLine(" Subject: {0}\n Data: {1}\n", msg.Subject, Encoding.UTF8.GetString(msg.Data)); Console.WriteLine(" " + msg.MetaData); // Because this is a synchronous subscriber, there's no auto-ack. // The default Consumer Configuration AckPolicy is Explicit // so we need to ack the message or it'll be redelivered. msg.Ack(); ++red; --count; } catch (NATSTimeoutException) // timeout means there are no messages available { count = 0; // ran out of messages } } Console.WriteLine("\n" + red + " message(s) were received.\n"); sub.Unsubscribe(); c.Flush(5000); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish With Options Use Cases", args, Usage) .DefaultStream("pubopts-stream") .DefaultSubject("pubopts-subject") .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // get a regular context IJetStream js = c.CreateJetStreamContext(); PublishOptions.PublishOptionsBuilder builder = PublishOptions.Builder() .WithExpectedStream(helper.Stream) .WithMessageId("mid1"); PublishAck pa = js.Publish(helper.Subject, Encoding.ASCII.GetBytes("message1"), builder.Build()); Console.WriteLine("Published message on subject {0}, stream {1}, seqno {2}.", helper.Subject, pa.Stream, pa.Seq); // IMPORTANT! // You can reuse the builder in 2 ways. // 1. Manually set a field to null or to DefaultLastSequence if you want to clear it out. // 2. Use the clearExpected method to clear the expectedLastId, expectedLastSequence and messageId fields // Manual re-use 1. Clearing some fields builder .WithExpectedLastMsgId("mid1") .WithExpectedLastSequence(PublishOptions.DefaultLastSequence) .WithMessageId(null); pa = js.Publish(helper.Subject, Encoding.ASCII.GetBytes("message2"), builder.Build()); Console.WriteLine("Published message on subject {0}, stream {1}, seqno {2}.", helper.Subject, pa.Stream, pa.Seq); // Manual re-use 2. Setting all the expected fields again builder .WithExpectedLastMsgId(null) .WithExpectedLastSequence(PublishOptions.DefaultLastSequence) .WithMessageId("mid3"); pa = js.Publish(helper.Subject, Encoding.ASCII.GetBytes("message3"), builder.Build()); Console.WriteLine("Published message on subject {0}, stream {1}, seqno {2}.", helper.Subject, pa.Stream, pa.Seq); // reuse() method clears all the fields, then we set some fields. builder.ClearExpected() .WithExpectedLastSequence(pa.Seq) .WithMessageId("mid4"); pa = js.Publish(helper.Subject, Encoding.ASCII.GetBytes("message4"), builder.Build()); Console.WriteLine("Published message on subject {0}, stream {1}, seqno {2}.", helper.Subject, pa.Stream, pa.Seq); // exception when the expected stream does not match [10060] try { PublishOptions errOpts = PublishOptions.Builder().WithExpectedStream("wrongStream").Build(); js.Publish(helper.Subject, Encoding.ASCII.GetBytes("ex1"), errOpts); } catch (NATSJetStreamException e) { Console.WriteLine($"Exception was: '{e.ErrorDescription}'"); } // exception with wrong last msg ID [10070] try { PublishOptions errOpts = PublishOptions.Builder().WithExpectedLastMsgId("wrongId").Build(); js.Publish(helper.Subject, Encoding.ASCII.GetBytes("ex2"), errOpts); } catch (NATSJetStreamException e) { Console.WriteLine($"Exception was: '{e.ErrorDescription}'"); } // exception with wrong last sequence wrong last sequence: 4 [10071] try { PublishOptions errOpts = PublishOptions.Builder().WithExpectedLastSequence(999).Build(); js.Publish(helper.Subject, Encoding.ASCII.GetBytes("ex3"), errOpts); } catch (NATSJetStreamException e) { Console.WriteLine($"Exception was: '{e.ErrorDescription}'"); } // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Manage Consumers", args, Usage) .DefaultStream("mcon-stream") .DefaultSubject("mcon-subject") .DefaultDurable("mcon-durable-") .Build(); try { string durable1 = helper.Durable + "1"; string durable2 = helper.Durable + "2"; using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // 1. Add Consumers Console.WriteLine("----------\n1. Configure And Add Consumers"); ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithDurable(durable1) // durable name is required when creating consumers .Build(); ConsumerInfo ci = jsm.AddOrUpdateConsumer(helper.Stream, cc); PrintConsumerInfo(ci); cc = ConsumerConfiguration.Builder() .WithDurable(durable2) .Build(); ci = jsm.AddOrUpdateConsumer(helper.Stream, cc); PrintObject(ci); // 2. get a list of ConsumerInfo's for all consumers Console.WriteLine("\n----------\n2. getConsumers"); IList <ConsumerInfo> consumers = jsm.GetConsumers(helper.Stream); PrintConsumerInfoList(consumers); // 3. get a list of all consumers Console.WriteLine("\n----------\n3. getConsumerNames"); IList <string> consumerNames = jsm.GetConsumerNames(helper.Stream); Console.WriteLine("Consumer Names: " + String.Join(",", consumerNames)); // 4. Delete a consumer, then list them again // Subsequent calls to deleteStream will throw a // NATSJetStreamException [10014] Console.WriteLine("\n----------\n4. Delete a consumer"); jsm.DeleteConsumer(helper.Stream, durable1); consumerNames = jsm.GetConsumerNames(helper.Stream); Console.WriteLine("Consumer Names: " + String.Join(",", consumerNames)); // 5. Try to delete the consumer again and get the exception Console.WriteLine("\n----------\n5. Delete consumer again"); try { jsm.DeleteConsumer(helper.Stream, durable1); } catch (NATSJetStreamException e) { Console.WriteLine($"Exception was: '{e.ErrorDescription}'"); } Console.WriteLine("\n----------"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Push Subscribe Basic Sync", args, Usage) .DefaultStream("example-stream") .DefaultSubject("example-subject") .DefaultCount(0, true) // true indicated 0 means unlimited // .DefaultDurable("push-sub-basic-sync-durable") .Build(); int count = helper.Count < 1 ? int.MaxValue : helper.Count; try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // The stream (and data) must exist JsUtils.ExitIfStreamNotExists(c, helper.Stream); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. // * A push subscription means the server will "push" us messages. // * Durable means the server will remember where we are if we use that name. // * Durable can by null or empty, the builder treats them the same. // * The stream name is not technically required. If it is not provided, the // code building the subscription will look it up by making a request to the server. // If you know the stream name, you might as well supply it and save a trip to the server. PushSubscribeOptions so = PushSubscribeOptions.Builder() .WithStream(helper.Stream) .WithDurable(helper.Durable) // it's okay if this is null, the builder handles it .Build(); // Subscribe synchronously, then just wait for messages. IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(helper.Subject, so); c.Flush(5000); int red = 0; while (count > 0) { try { Msg msg = sub.NextMessage(1000); Console.WriteLine("\nMessage Received:"); if (msg.HasHeaders) { Console.WriteLine(" Headers:"); foreach (string key in msg.Header.Keys) { foreach (string value in msg.Header.GetValues(key)) { Console.WriteLine($" {key}: {value}"); } } } Console.WriteLine(" Subject: {0}\n Data: {1}\n", msg.Subject, Encoding.UTF8.GetString(msg.Data)); Console.WriteLine(" " + msg.MetaData); // Because this is a synchronous subscriber, there's no auto-ack. // The default Consumer Configuration AckPolicy is Explicit // so we need to ack the message or it'll be redelivered. msg.Ack(); ++red; --count; } catch (NATSTimeoutException) // timeout means there are no messages available { count = 0; // ran out of messages } } Console.WriteLine("\n" + red + " message(s) were received.\n"); sub.Unsubscribe(); c.Flush(5000); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Expires In", args, Usage) .DefaultStream("expires-in-stream") .DefaultSubject("expires-in-subject") .DefaultDurable("expires-in-durable") .DefaultCount(15) .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Start publishing the messages, don't wait for them to finish, simulating an outside producer. JsUtils.PublishInBackground(js, helper.Subject, "expires-in-message", helper.Count); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .Build(); // subscribe IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); bool keepGoing = true; int red = 0; while (keepGoing && red < helper.Count) { sub.PullExpiresIn(10, 1000); int round = 0; while (keepGoing && round < 10) { try { Msg m = sub.NextMessage(1000); // first message Console.WriteLine($"{++red}. Message: {m}"); m.Ack(); round++; } catch (NATSTimeoutException) // timeout means there are no messages available { keepGoing = false; } } } // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("JetStream Publish Async", args, Usage) .DefaultStream("example-stream") .DefaultSubject("example-subject") .DefaultPayload("Hello") .DefaultCount(10) .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Use the utility to create a stream stored in memory. JsUtils.CreateStreamOrUpdateSubjects(c, helper.Stream, helper.Subject); // create a JetStream context IJetStream js = c.CreateJetStreamContext(); IList <Task <PublishAck> > tasks = new List <Task <PublishAck> >(); int stop = helper.Count < 2 ? 2 : helper.Count + 1; for (int x = 1; x < stop; x++) { // make unique message data if you want more than 1 message byte[] data = helper.Count < 2 ? Encoding.UTF8.GetBytes(helper.Payload) : Encoding.UTF8.GetBytes(helper.Payload + "-" + x); // Publish a message and print the results of the publish acknowledgement. Msg msg = new Msg(helper.Subject, null, helper.Header, data); // We'll use the defaults for this simple example, but there are options // to constrain publishing to certain streams, expect sequence numbers and // more. See the JetStreamPublishWithOptionsUseCases example for details. // An exception will be thrown if there is a failure. tasks.Add(js.PublishAsync(msg)); while (tasks.Count > 0) { Task <PublishAck> task = tasks[0]; tasks.RemoveAt(0); if (task.IsCompleted) { try { PublishAck pa = task.Result; Console.WriteLine("Published message {0} on subject {1}, stream {2}, seqno {3}.", Encoding.UTF8.GetString(data), helper.Subject, pa.Stream, pa.Seq); } catch (Exception e) { Console.WriteLine("Publish Failed: " + e); } } else { // re queue so will be checked for completed again tasks.Add(task); } } } } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive No Wait, Use Cases", args, Usage) .DefaultStream("nowait-uc-stream") .DefaultSubject("nowait-uc-subject") .DefaultDurable("nowait-uc-durable") .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .Build(); // 0.1 Initialize. subscription // 0.2 DO NOT start the pull, no wait works differently than regular pull. // With no wait, we have to start the pull the first time and every time the // batch size is exhausted or no waits out. // 0.3 Flush outgoing communication with/to the server, useful when app is both publishing and subscribing. Console.WriteLine("\n----------\n0. Initialize the subscription and pull."); IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); // 1. Start the pull, but there are no messages yet. // - Read the messages // - Since there are less than the batch size, we get them all (0) Console.WriteLine("----------\n1. There are no messages yet"); sub.PullNoWait(10); IList <Msg> messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); // 2. Publish 10 messages // - Start the pull // - Read the messages // - Since there are exactly the batch size we get them all Console.WriteLine("----------\n2. Publish 10 which satisfies the batch"); JsUtils.Publish(js, helper.Subject, "A", 10); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 3. Publish 20 messages // - Start the pull // - Read the messages Console.WriteLine("----------\n3. Publish 20 which is larger than the batch size."); JsUtils.Publish(js, helper.Subject, "B", 20); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 4. There are still messages left from the last // - Start the pull // - Read the messages Console.WriteLine("----------\n4. Get the rest of the publish."); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 5. Publish 5 messages // - Start the pull // - Read the messages Console.WriteLine("----------\n5. Publish 5 which is less than batch size."); JsUtils.Publish(js, helper.Subject, "C", 5); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 5 total messages, we received: " + messages.Count); // 6. Publish 14 messages // - Start the pull // - Read the messages // - we do NOT get a nowait status message if there are more or equals messages than the batch Console.WriteLine("----------\n6. Publish 14 which is more than the batch size."); JsUtils.Publish(js, helper.Subject, "D", 14); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 10 total messages, we received: " + messages.Count); // 7. There are 4 messages left // - Start the pull // - Read the messages // - Since there are less than batch size the last message we get will be a status 404 message. Console.WriteLine("----------\n7. There are 4 messages left, which is less than the batch size."); sub.PullNoWait(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 4 messages, we received: " + messages.Count); Console.WriteLine("----------\n"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("NATS JetStream Push Subscribe Queue Durable", args, Usage) .DefaultStream("qdur-stream") .DefaultSubject("qdur-subject") .DefaultQueue("qdur-queue") .DefaultDurable("qdur-durable") .DefaultDeliverSubject("qdur-deliver") .DefaultCount(100) .DefaultSubsCount(5) .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); IJetStream js = c.CreateJetStreamContext(); Console.WriteLine(); // create the consumer ahead of time ConsumerConfiguration cc = ConsumerConfiguration.Builder() .WithDurable(helper.Durable) .WithDeliverSubject(helper.DeliverSubject) .WithDeliverGroup(helper.Queue) .Build(); jsm.AddOrUpdateConsumer(helper.Stream, cc); // we will just bind to that consumer PushSubscribeOptions pso = PushSubscribeOptions.BindTo(helper.Stream, helper.Durable); InterlockedLong allReceived = new InterlockedLong(); IList <JsQueueSubscriber> subscribers = new List <JsQueueSubscriber>(); IList <Thread> subThreads = new List <Thread>(); for (int id = 1; id <= helper.SubsCount; id++) { // setup the subscription IJetStreamPushSyncSubscription sub = js.PushSubscribeSync(helper.Subject, helper.Queue, pso); // create and track the runnable JsQueueSubscriber qs = new JsQueueSubscriber(id, 100, js, sub, allReceived); subscribers.Add(qs); // create, track and start the thread Thread t = new Thread(qs.Run); subThreads.Add(t); t.Start(); } c.Flush(500); // flush outgoing communication with/to the server // create and start the publishing Thread pubThread = new Thread(() => { for (int x = 1; x <= helper.Count; x++) { js.Publish(helper.Subject, Encoding.ASCII.GetBytes("Data # " + x)); } }); pubThread.Start(); // wait for all threads to finish pubThread.Join(10000); foreach (Thread t in subThreads) { t.Join(10000); } foreach (JsQueueSubscriber qs in subscribers) { qs.Report(); } Console.WriteLine(); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }
public static void Main(string[] args) { ArgumentHelper helper = new ArgumentHelperBuilder("Pull Subscription using primitive Batch Size, Use Cases", args, Usage) .DefaultStream("pull-stream") .DefaultSubject("pull-subject") .DefaultDurable("pull-durable") .Build(); try { using (IConnection c = new ConnectionFactory().CreateConnection(helper.MakeOptions())) { // Create a JetStreamManagement context. IJetStreamManagement jsm = c.CreateJetStreamManagementContext(); // Use the utility to create a stream stored in memory. JsUtils.CreateStreamExitWhenExists(jsm, helper.Stream, helper.Subject); // Create our JetStream context. IJetStream js = c.CreateJetStreamContext(); // Build our subscription options. Durable is REQUIRED for pull based subscriptions PullSubscribeOptions pullOptions = PullSubscribeOptions.Builder() .WithDurable(helper.Durable) // required .Build(); // 0.1 Initialize. subscription // 0.2 Flush outgoing communication with/to the server, useful when app is both JsUtils.Publishing and subscribing. // 0.3 Start the pull, you don't have to call this again because AckMode.NEXT // - When we ack a batch message the server starts preparing or adding to the next batch. Console.WriteLine("\n----------\n0. Initialize the subscription and pull."); IJetStreamPullSubscription sub = js.PullSubscribe(helper.Subject, pullOptions); c.Flush(1000); sub.Pull(10); // 1. JsUtils.Publish some that is less than the batch size. // - Do this first as data will typically be published first. Console.WriteLine("----------\n1. JsUtils.Publish some amount of messages, but not entire batch size."); JsUtils.Publish(js, helper.Subject, "A", 4); IList <Msg> messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 4 total messages, we received: " + messages.Count); // 2. JsUtils.Publish some more covering our pull size... // - Read what is available, expect only 6 b/c 4 + 6 = 10 Console.WriteLine("----------\n2. JsUtils.Publish more than the remaining batch size."); JsUtils.Publish(js, helper.Subject, "B", 10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 6 total messages, we received: " + messages.Count); // 3. There are still 4 messages from B, but the batch was finished // - won't get any messages until a pull is issued. Console.WriteLine("----------\n3. Read without re-issue."); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 0 total messages, we received: " + messages.Count); // 4. re-issue the pull to get the last 4 Console.WriteLine("----------\n4. Re-issue to get the last 4."); sub.Pull(10); messages = JsUtils.ReadMessagesAck(sub); Console.WriteLine("We should have received 4 total messages, we received: " + messages.Count); Console.WriteLine("----------\n"); // delete the stream since we are done with it. jsm.DeleteStream(helper.Stream); } } catch (Exception ex) { helper.ReportException(ex); } }