• Stars
    star
    149
  • Rank 240,290 (Top 5 %)
  • Language
    TypeScript
  • License
    Apache License 2.0
  • Created almost 4 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Deno client for NATS, the cloud native messaging system

NATS.deno - A NATS client for Deno

A Deno client for the NATS messaging system.

License Test NATS.deno Coverage Status

Installation

You can get the latest release version like this:

import * as nats from "https://deno.land/x/nats/src/mod.ts";

To specify a specific released version, simply replace nats with nats@versionTag.

You can get the current development version by:

import * as nats from "https://raw.githubusercontent.com/nats-io/nats.deno/main/src/mod.ts";

Documentation

While the best documentation is looking at code examples, you may want to browse the JSDoc documentation. The best entry point into the JS Doc is the NatsConnection all functionality starts with a connection.

Basics

Connecting to a nats-server

To connect to a server you use the connect() function. It returns a connection that you can use to interact with the server. You can customize the behavior of the client by specifying many ConnectionOptions.

By default, a connection will attempt a connection on 127.0.0.1:4222. If the connection is dropped, the client will attempt to reconnect. You can customize the server you want to connect to by specifying port (for local connections), or full host port on the servers option. Note that the servers option can be a single hostport (a string) or an array of hostports.

The example below will attempt to connect to different servers by specifying different ConnectionOptions. At least two of them should work if your internet is working.

// import the connect function
import { connect } from "../../src/mod.ts";

const servers = [
  {},
  { servers: ["demo.nats.io:4442", "demo.nats.io:4222"] },
  { servers: "demo.nats.io:4443" },
  { port: 4222 },
  { servers: "localhost" },
];
await servers.forEach(async (v) => {
  try {
    const nc = await connect(v);
    console.log(`connected to ${nc.getServer()}`);
    // this promise indicates the client closed
    const done = nc.closed();
    // do something with the connection

    // close the connection
    await nc.close();
    // check if the close was OK
    const err = await done;
    if (err) {
      console.log(`error closing:`, err);
    }
  } catch (err) {
    console.log(`error connecting to ${JSON.stringify(v)}`);
  }
});

To disconnect from the nats-server, call close() on the connection. A connection can also be terminated when an unexpected error happens. For example, the server returns a run-time error. In those cases, the client will re-initiate a connection.

By default, the client will always attempt to reconnect if the connection is closed for a reason other than calling close(). To get notified when the connection is closed for some reason, await the resolution of the Promise returned by closed(). If closed resolves to a value, the value is a NatsError indicating why the connection closed.

Publish and Subscribe

The basic client operations are publish to send messages and subscribe to receive messages.

Messages are published to a subject. A subject is like an URL with the exception that it doesn't specify an actual endpoint. All recipients that have expressed interest in a subject will receive messages addressed to that subject (provided they have access and permissions to get it). To express interest in a subject, you create a subscription.

In JavaScript clients (websocket, Deno, or Node) subscriptions work as an async iterator - clients simply loop to process messages as they become available.

NATS messages are payload agnostic. Payloads are Uint8Arrays. You can easily convert to and from JSON or strings by using JSONCodec or StringCodec, or a custom Codec.

To cancel a subscription and terminate your interest, you call unsubscribe() or drain() on a subscription. Unsubscribe will typically terminate regardless of whether there are messages in flight for the client. Drain ensures that all messages that are inflight are processed before canceling the subscription. Connections can also be drained as well. Draining a connection closes it, after all subscriptions have been drained and all outbound messages have been sent to the server.

// import the connect function
import { connect, StringCodec } from "../../src/mod.ts";

// to create a connection to a nats-server:
const nc = await connect({ servers: "demo.nats.io:4222" });

// create a codec
const sc = StringCodec();
// create a simple subscriber and iterate over messages
// matching the subscription
const sub = nc.subscribe("hello");
(async () => {
  for await (const m of sub) {
    console.log(`[${sub.getProcessed()}]: ${sc.decode(m.data)}`);
  }
  console.log("subscription closed");
})();

nc.publish("hello", sc.encode("world"));
nc.publish("hello", sc.encode("again"));

// we want to insure that messages that are in flight
// get processed, so we are going to drain the
// connection. Drain is the same as close, but makes
// sure that all messages in flight get seen
// by the iterator. After calling drain on the connection
// the connection closes.
await nc.drain();

JSONCodec allows you to encode and decode JSON and if you are using typescript, you can even use generics to have the compiler help you:

// create a codec
const sc = JSONCodec<Person>();

// create a simple subscriber and iterate over messages
// matching the subscription
const sub = nc.subscribe("people");
(async () => {
  for await (const m of sub) {
    // typescript will see this as a Person
    const p = sc.decode(m.data);
    console.log(`[${sub.getProcessed()}]: ${p.name}`);
  }
})();

// if you made a typo or added other properties
// the compiler will get angry
const p = { name: "Memo" } as Person;
nc.publish("people", sc.encode(p));

Wildcard Subscriptions

Subjects can be used to organize messages into hierarchies. For example, a subject may contain additional information that can be useful in providing a context to the message, such as the ID of the client that sent the message, or the region where a message originated.

Instead of subscribing to each specific subject, you can create subscriptions that have subjects with wildcards. Wildcards match one or more tokens in a subject. A token is a string following a period.

All subscriptions are independent. If two different subscriptions match a subject, both will get to process the message:

import { connect, StringCodec, Subscription } from "../../src/mod.ts";
const nc = await connect({ servers: "demo.nats.io:4222" });
const sc = StringCodec();

// subscriptions can have wildcard subjects
// the '*' matches any string in the specified token position
const s1 = nc.subscribe("help.*.system");
const s2 = nc.subscribe("help.me.*");
// the '>' matches any tokens in that position or following
// '>' can only be specified at the end of the subject
const s3 = nc.subscribe("help.>");

async function printMsgs(s: Subscription) {
  let subj = s.getSubject();
  console.log(`listening for ${subj}`);
  const c = (13 - subj.length);
  const pad = "".padEnd(c);
  for await (const m of s) {
    console.log(
      `[${subj}]${pad} #${s.getProcessed()} - ${m.subject} ${
        m.data ? " " + sc.decode(m.data) : ""
      }`,
    );
  }
}

printMsgs(s1);
printMsgs(s2);
printMsgs(s3);

// don't exit until the client closes
await nc.closed();

Services: Request/Reply

Request/Reply is NATS equivalent to an HTTP request. To make requests you publish messages as you did before, but also specify a reply subject. The reply subject is where a service will publish your response.

NATS provides syntactic sugar, for publishing requests. The request() API will generate a reply subject and manage the creation of a subscription under the covers. It will also start a timer to ensure that if a response is not received within your alloted time, the request fails. The example also illustrates a graceful shutdown.

Services

Here's an example of a service. It is a bit more complicated than expected simply to illustrate not only how to create responses, but how the subject itself is used to dispatch different behaviors.

import { connect, StringCodec, Subscription } from "../../src/mod.ts";

// create a connection
const nc = await connect({ servers: "demo.nats.io" });

// create a codec
const sc = StringCodec();

// this subscription listens for `time` requests and returns the current time
const sub = nc.subscribe("time");
(async (sub: Subscription) => {
  console.log(`listening for ${sub.getSubject()} requests...`);
  for await (const m of sub) {
    if (m.respond(sc.encode(new Date().toISOString()))) {
      console.info(`[time] handled #${sub.getProcessed()}`);
    } else {
      console.log(`[time] #${sub.getProcessed()} ignored - no reply subject`);
    }
  }
  console.log(`subscription ${sub.getSubject()} drained.`);
})(sub);

// this subscription listens for admin.uptime and admin.stop
// requests to admin.uptime returns how long the service has been running
// requests to admin.stop gracefully stop the client by draining
// the connection
const started = Date.now();
const msub = nc.subscribe("admin.*");
(async (sub: Subscription) => {
  console.log(`listening for ${sub.getSubject()} requests [uptime | stop]`);
  // it would be very good to verify the origin of the request
  // before implementing something that allows your service to be managed.
  // NATS can limit which client can send or receive on what subjects.
  for await (const m of sub) {
    const chunks = m.subject.split(".");
    console.info(`[admin] #${sub.getProcessed()} handling ${chunks[1]}`);
    switch (chunks[1]) {
      case "uptime":
        // send the number of millis since up
        m.respond(sc.encode(`${Date.now() - started}`));
        break;
      case "stop": {
        m.respond(sc.encode(`[admin] #${sub.getProcessed()} stopping....`));
        // gracefully shutdown
        nc.drain()
          .catch((err) => {
            console.log("error draining", err);
          });
        break;
      }
      default:
        console.log(
          `[admin] #${sub.getProcessed()} ignoring request for ${m.subject}`,
        );
    }
  }
  console.log(`subscription ${sub.getSubject()} drained.`);
})(msub);

// wait for the client to close here.
await nc.closed().then((err?: void | Error) => {
  let m = `connection to ${nc.getServer()} closed`;
  if (err) {
    m = `${m} with an error: ${err.message}`;
  }
  console.log(m);
});

Making Requests

Here's a simple example of a client making a simple request from the service above:

import { connect, Empty, StringCodec } from "../../src/mod.ts";

// create a connection
const nc = await connect({ servers: "demo.nats.io:4222" });

// create an encoder
const sc = StringCodec();

// the client makes a request and receives a promise for a message
// by default the request times out after 1s (1000 millis) and has
// no payload.
await nc.request("time", Empty, { timeout: 1000 })
  .then((m) => {
    console.log(`got response: ${sc.decode(m.data)}`);
  })
  .catch((err) => {
    console.log(`problem with request: ${err.message}`);
  });

await nc.close();

Queue Groups

Queue groups allow scaling of services horizontally. Subscriptions for members of a queue group are treated as a single service. When you send a message to a queue group subscription, only a single client in a queue group will receive it.

There can be any number of queue groups. Each group is treated as its own independent unit. Note that non-queue subscriptions are also independent of subscriptions in a queue group.

import {
  connect,
  NatsConnection,
  StringCodec,
  Subscription,
} from "../../src/mod.ts";

// this is the definition of a service with `count` members in them.
// if the queue is specified, the they will be part of a queue
async function createService(
  name: string,
  count: number = 1,
  queue: string = "",
): Promise<NatsConnection[]> {
  const conns: NatsConnection[] = [];
  for (let i = 1; i <= count; i++) {
    const n = queue ? `${name}-${i}` : name;
    const nc = await connect(
      { servers: "demo.nats.io:4222", name: `${n}` },
    );
    nc.closed()
      .then((err) => {
        if (err) {
          console.error(
            `service ${n} exited because of error: ${err.message}`,
          );
        }
      });
    // create a subscription - note the option for a queue, if set
    // any client with the same queue will be a member of the group.
    const sub = nc.subscribe("echo", { queue: queue });
    const _ = handleRequest(n, sub);
    console.log(`${nc.options.name} is listening for 'echo' requests...`);
    conns.push(nc);
  }
  return conns;
}

const sc = StringCodec();

// simple handler for service requests
async function handleRequest(name: string, s: Subscription) {
  const p = 12 - name.length;
  const pad = "".padEnd(p);
  for await (const m of s) {
    // respond returns true if the message had a reply subject, thus it could respond
    if (m.respond(m.data)) {
      console.log(
        `[${name}]:${pad} #${s.getProcessed()} echoed ${sc.decode(m.data)}`,
      );
    } else {
      console.log(
        `[${name}]:${pad} #${s.getProcessed()} ignoring request - no reply subject`,
      );
    }
  }
}

// let's create two queue groups and a standalone subscriber
const conns: NatsConnection[] = [];
conns.push(...await createService("echo", 3, "echo"));
conns.push(...await createService("other-echo", 2, "other-echo"));
conns.push(...await createService("standalone"));

const a: Promise<void | Error>[] = [];
conns.forEach((c) => {
  a.push(c.closed());
});
await Promise.all(a);

Run it and publish a request to the subject echo to see what happens.

Advanced Usage

Headers

NATS headers are similar to HTTP headers. Headers are enabled automatically if the server supports them. Note that if you publish a message using headers but the server doesn't support them, an Error is thrown. Also note that even if you are publishing a message with a header, it is possible for the recipient to not support them.

import { connect, createInbox, Empty, headers } from "../../src/mod.ts";
import { nuid } from "../../nats-base-client/nuid.ts";

const nc = await connect(
  {
    servers: `demo.nats.io`,
  },
);

const subj = createInbox();
const sub = nc.subscribe(subj);
(async () => {
  for await (const m of sub) {
    if (m.headers) {
      for (const [key, value] of m.headers) {
        console.log(`${key}=${value}`);
      }
      // reading a header is not case sensitive
      console.log("id", m.headers.get("id"));
    }
  }
})().then();

// header names can be any printable ASCII character with the  exception of `:`.
// header values can be any ASCII character except `\r` or `\n`.
// see https://www.ietf.org/rfc/rfc822.txt
const h = headers();
h.append("id", nuid.next());
h.append("unix_time", Date.now().toString());
nc.publish(subj, Empty, { headers: h });

await nc.flush();
await nc.close();

No Responders

Requests can fail for many reasons. A common reason for a failure is the lack of interest in the subject. Typically these surface as a timeout error. If the server is enabled to use headers, it will also enable a no responders feature. If you send a request for which there's no interest, the request will be immediately rejected:

const nc = await connect({
  servers: `demo.nats.io`,
});

try {
  const m = await nc.request("hello.world");
  console.log(m.data);
} catch (err) {
  const nerr = err as NatsError;
  switch (nerr.code) {
    case ErrorCode.NoResponders:
      console.log("no one is listening to 'hello.world'");
      break;
    case ErrorCode.Timeout:
      console.log("someone is listening but didn't respond");
      break;
    default:
      console.log("request failed", err);
  }
}

await nc.close();

Authentication

NATS supports many different forms of credentials:

  • username/password
  • token
  • NKEYS
  • client certificates
  • JWTs

For user/password and token authentication, you can simply provide them as ConnectionOptions - see user, pass, token. Internally these mechanisms are implemented as an Authenticator. An Authenticator is simply a function that handles the type of authentication specified.

Setting the user/pass or token options, simply initializes an Authenticator and sets the username/password.

// if the connection requires authentication, provide `user` and `pass` or
// `token` options in the NatsConnectionOptions
import { connect } from "src/mod.ts";

const nc1 = await connect({
  servers: "127.0.0.1:4222",
  user: "jenny",
  pass: "867-5309",
});
const nc2 = await connect({ port: 4222, token: "t0pS3cret!" });

Authenticators

NKEYs and JWT authentication are more complex, as they cryptographically respond to a server challenge.

Because NKEY and JWT authentication may require reading data from a file or an HTTP cookie, these forms of authentication will require a bit more from the developer to activate them. However, the work is related to accessing these resources varies depending on the platform.

After the credential artifacts are read, you can use one of these functions to create the authenticator. You then simply assign it to the authenticator property of the ConnectionOptions:

  • nkeyAuthenticator(seed?: Uint8Array | (() => Uint8Array)): Authenticator
  • jwtAuthenticator(jwt: string | (() => string), seed?: Uint8Array | (()=> Uint8Array)): Authenticator
  • credsAuthenticator(creds: Uint8Array): Authenticator

The first two options provide the ability to specify functions that return the desired value. This enables dynamic environments such as a browser where values accessed by fetching a value from a cookie.

Here's an example:

// read the creds file as necessary, in the case it
// is part of the code for illustration purposes
const creds = `-----BEGIN NATS USER JWT-----
    eyJ0eXAiOiJqdSDJB....
  ------END NATS USER JWT------

************************* IMPORTANT *************************
  NKEY Seed printed below can be used sign and prove identity.
  NKEYs are sensitive and should be treated as secrets.

  -----BEGIN USER NKEY SEED-----
    SUAIBDPBAUTW....
  ------END USER NKEY SEED------
`;

const nc = await connect(
  {
    port: 4222,
    authenticator: credsAuthenticator(new TextEncoder().encode(creds)),
  },
);

Flush

Flush sends a PING to the server. When the server responds with PONG you are guaranteed that all pending data was sent and received by the server. Note ping() effectively adds a server round-trip. All NATS clients handle their buffering optimally, so ping(): Promise<void> shouldn't be used except in cases where you are writing some sort of test.

nc.publish("foo");
nc.publish("bar");
await nc.flush();

PublishOptions

When you publish a message you can specify some options:

  • reply - this is a subject to receive a reply (you must setup a subscription) before you publish.
  • headers - a set of headers to decorate the message.

SubscriptionOptions

You can specify several options when creating a subscription:

  • max: maximum number of messages to receive - auto unsubscribe
  • timeout: how long to wait for the first message
  • queue: the queue group name the subscriber belongs to
  • callback: a function with the signature (err: NatsError|null, msg: Msg) => void; that should be used for handling the message. Subscriptions with callbacks are NOT iterators.

Auto Unsubscribe

// subscriptions can auto unsubscribe after a certain number of messages
nc.subscribe("foo", { max: 10 });

Timeout Subscriptions

// create subscription with a timeout, if no message arrives
// within the timeout, the function running the iterator with
// reject - depending on how you code it, you may need a
// try/catch block.
const sub = nc.subscribe("hello", { timeout: 1000 });
(async () => {
  for await (const m of sub) {
  }
})().catch((err) => {
  if (err.code === ErrorCode.Timeout) {
    console.log(`sub timed out!`);
  } else {
    console.log(`sub iterator got an error!`);
  }
});

RequestOptions

When making a request, there are several options you can pass:

  • timeout: how long to wait for the response
  • headers: optional headers to include with the message
  • noMux: create a new subscription to handle the request. Normally a shared subscription is used to receive response messages.
  • reply: optional subject where the reply should be sent.

noMux and reply

Under the hood, the request API simply uses a wildcard subscription to handle all requests you send.

In some cases, the default subscription strategy doesn't work correctly. For example, a client may be constrained by the subjects where it can receive replies.

When noMux is set to true, the client will create a normal subscription for receiving the response to a generated inbox subject before the request is published. The reply option can be used to override the generated inbox subject with an application provided one. Note that setting reply requires noMux to be true:

const m = await nc.request(
  "q",
  Empty,
  { reply: "bar", noMux: true, timeout: 1000 },
);

Draining Connections and Subscriptions

Draining provides for a graceful way to unsubscribe or close a connection without losing messages that have already been dispatched to the client.

You can drain a subscription or all subscriptions in a connection.

When you drain a subscription, the client sends an unsubscribe protocol message to the server followed by a flush. The subscription handler is only removed after the server responds. Thus all pending messages for the subscription have been processed.

Draining a connection, drains all subscriptions. However when you drain the connection it becomes impossible to make new subscriptions or send new requests. After the last subscription is drained it also becomes impossible to publish a message. These restrictions do not exist when just draining a subscription.

Lifecycle/Informational Events

Clients can get notification on various event types:

  • Events.DISCONNECT
  • Events.RECONNECT
  • Events.UPDATE
  • Events.LDM
  • Events.ERROR

The first two fire when a client disconnects and reconnects respectively. The payload will be the server where the event took place.

The UPDATE event notifies whenever the client receives a cluster configuration update. The ServersChanged interface provides two arrays: added and deleted listing the servers that were added or removed.

The LDM event notifies that the current server has signaled that it is running in Lame Duck Mode and will evict clients. Depending on the server configuration policy, the client may want to initiate an ordered shutdown, and initiate a new connection to a different server in the cluster.

The ERROR event notifies you of async errors that couldn't be routed in a more precise way to your client. For example, permission errors for a subscription or request, will properly be reported by the subscription or request. However, permission errors on publish will be reported via the status mechanism.

const nc = await connect(opts);
(async () => {
  console.info(`connected ${nc.getServer()}`);
  for await (const s of nc.status()) {
    console.info(`${s.type}: ${s.data}`);
  }
})().then();

nc.closed()
  .then((err) => {
    console.log(
      `connection closed ${err ? " with error: " + err.message : ""}`,
    );
  });

Be aware that when a client closes, you will need to wait for the closed() promise to resolve. When it resolves, the client is done and will not reconnect.

Async vs. Callbacks

Previous versions of the JavaScript NATS clients specified callbacks for message processing. This required complex handling logic when a service required coordination of operations. Callbacks are an inversion of control anti-pattern.

The async APIs trivialize complex coordination and makes your code easier to maintain. With that said, there are some implications:

  • Async subscriptions buffer inbound messages.
  • Subscription processing delays until the runtime executes the promise related microtasks at the end of an event loop.

In a traditional callback-based library, I/O happens after all data yielded by a read in the current event loop completes processing. This means that callbacks are invoked as part of processing. With async, the processing is queued in a microtask queue. At the end of the event loop, the runtime processes the microtasks, which in turn resumes your functions. As expected, this increases latency, but also provides additional liveliness.

To reduce async latency, the NATS client allows processing a subscription in the same event loop that dispatched the message. Simply specify a callback in the subscription options. The signature for a callback is (err: (NatsError|null), msg: Msg) => void. When specified, the subscription iterator will never yield a message, as the callback will intercept all messages.

Note that callback likely shouldn't even be documented, as likely it is a workaround to an underlying application problem where you should be considering a different strategy to horizontally scale your application, or reduce pressure on the clients, such as using queue workers, or more explicitly targeting messages. With that said, there are many situations where using callbacks can be more performant or appropriate.

Connection Options

The following is the list of connection options and default values.

Option Default Description
authenticator none Specifies the authenticator function that sets the client credentials.
debug false If true, the client prints protocol interactions to the console. Useful for debugging.
ignoreClusterUpdates false If true the client will ignore any cluster updates provided by the server.
inboxPrefix "_INBOX" Sets de prefix for automatically created inboxes - createInbox(prefix)
maxPingOut 2 Max number of pings the client will allow unanswered before raising a stale connection error.
maxReconnectAttempts 10 Sets the maximum number of reconnect attempts. The value of -1 specifies no limit.
name Optional client name - recommended to be set to a unique client name.
noEcho false Subscriptions receive messages published by the client. Requires server support (1.2.0). If set to true, and the server does not support the feature, an error with code NO_ECHO_NOT_SUPPORTED is emitted, and the connection is aborted. Note that it is possible for this error to be emitted on reconnect when the server reconnects to a server that does not support the feature.
noRandomize false If set, the order of user-specified servers is randomized.
pass Sets the password for a connection.
pedantic false Turns on strict subject format checks.
pingInterval 120000 Number of milliseconds between client-sent pings.
port 4222 Port to connect to (only used if servers is not specified).
reconnect true If false, client will not attempt reconnecting.
reconnectDelayHandler Generated function A function that returns the number of millis to wait before the next connection to a server it connected to ()=>number.
reconnectJitter 100 Number of millis to randomize after reconnectTimeWait.
reconnectJitterTLS 1000 Number of millis to randomize after reconnectTimeWait when TLS options are specified.
reconnectTimeWait 2000 If disconnected, the client will wait the specified number of milliseconds between reconnect attempts.
servers "localhost:4222" String or Array of hostport for servers.
timeout 20000 Number of milliseconds the client will wait for a connection to be established. If it fails it will emit a connection_timeout event with a NatsError that provides the hostport of the server where the connection was attempted.
tls TlsOptions A configuration object for requiring a TLS connection (not applicable to nats.ws).
token Sets a authorization token for a connection.
user Sets the username for a connection.
verbose false Turns on +OK protocol acknowledgements.
waitOnFirstConnect false If true the client will fall back to a reconnect mode if it fails its first connection attempt.

TlsOptions

Option Default Description
ca N/A CA certificate
caFile CA certificate filepath
cert N/A Client certificate
certFile N/A Client certificate file path
key N/A Client key
keyFile N/A Client key file path

In some Node and Deno clients, having the option set to an empty option, requires the client have a secured connection.

Jitter

The settings reconnectTimeWait, reconnectJitter, reconnectJitterTLS, reconnectDelayHandler are all related. They control how long before the NATS client attempts to reconnect to a server it has previously connected.

The intention of the settings is to spread out the number of clients attempting to reconnect to a server over a period of time, and thus preventing a "Thundering Herd".

The relationship between these is:

  • If reconnectDelayHandler is specified, the client will wait the value returned by this function. No other value will be taken into account.
  • If the client specified TLS options, the client will generate a number between 0 and reconnectJitterTLS and add it to reconnectTimeWait.
  • If the client didn't specify TLS options, the client will generate a number between 0 and reconnectJitter and add it to reconnectTimeWait.

JetStream

JetStream is the NATS persistence engine providing streaming, message, and worker queues with At-Least-Once semantics. Support for JetStream is built-in.

Service API

The service API allows you to easily build NATS services The services API is currently in beta functionality.

More Repositories

1

nats-server

High-Performance server for NATS.io, the cloud and edge native messaging system.
Go
14,523
star
2

nats.go

Golang client for NATS, the cloud native messaging system.
Go
5,149
star
3

nats-streaming-server

NATS Streaming System Server
Go
2,495
star
4

nats.js

Node.js client for NATS, the cloud native messaging system.
JavaScript
1,477
star
5

nats.rs

Rust client for NATS, the cloud native messaging system.
Rust
933
star
6

nats.rb

Ruby client for NATS, the cloud native messaging system.
Ruby
880
star
7

nats.py

Python3 client for NATS
Python
797
star
8

stan.go

NATS Streaming System
Go
705
star
9

nats.net

The official C# Client for NATS
C#
639
star
10

nats-operator

NATS Operator
Go
571
star
11

nats.java

Java client for NATS
Java
541
star
12

jetstream

JetStream Utilities
Dockerfile
452
star
13

k8s

NATS on Kubernetes with Helm Charts
Go
416
star
14

natscli

The NATS Command Line Interface
Go
414
star
15

nats.c

A C client for NATS
C
367
star
16

nuid

NATS Unique Identifiers
Go
357
star
17

prometheus-nats-exporter

A Prometheus exporter for NATS metrics
Go
344
star
18

nats-top

A top-like tool for monitoring NATS servers.
Go
331
star
19

stan.js

Node.js client for NATS Streaming
JavaScript
293
star
20

nats.ws

WebSocket NATS
JavaScript
290
star
21

nats-surveyor

NATS Monitoring, Simplified.
Go
204
star
22

nats.ex

Elixir client for NATS, the cloud native messaging system. https://nats.io
Elixir
189
star
23

nats.ts

TypeScript Node.js client for NATS, the cloud native messaging system
TypeScript
178
star
24

graft

A RAFT Election implementation in Go.
Go
176
star
25

nats-streaming-operator

NATS Streaming Operator
Go
173
star
26

nats.net.v2

Full Async C# / .NET client for NATS
C#
170
star
27

nats-architecture-and-design

Architecture and Design Docs
Go
164
star
28

nack

NATS Controllers for Kubernetes (NACK)
Go
139
star
29

stan.net

The official NATS .NET C# Streaming Client
C#
137
star
30

jsm.go

JetStream Management Library for Golang
Go
132
star
31

nats-docker

Official Docker image for the NATS server
Dockerfile
123
star
32

nkeys

NATS Keys
Go
120
star
33

nats-pure.rb

Ruby client for NATS, the cloud native messaging system.
Ruby
117
star
34

nats-kafka

NATS to Kafka Bridging
Go
116
star
35

stan.py

Python Asyncio NATS Streaming Client
Python
113
star
36

nats.zig

Zig Client for NATS
109
star
37

go-nats-examples

Single repository for go-nats example code. This includes all documentation examples and any common message pattern examples.
Go
108
star
38

nginx-nats

NGINX client module for NATS, the cloud native messaging system.
C
105
star
39

nats.docs

NATS.io Documentation on Gitbook
HTML
103
star
40

nats-box

A container with NATS utilities
HCL
99
star
41

stan.java

NATS Streaming Java Client
Java
92
star
42

not.go

A reference for distributed tracing with the NATS Go client.
Go
91
star
43

nsc

Tool for creating nkey/jwt based configurations
Go
88
star
44

nats-site

Website content for https://nats.io. For technical issues with NATS products, please log an issue in the proper repository.
Markdown
87
star
45

jparse

Small, Fast, Compliant JSON parser that uses events parsing and index overlay
Java
86
star
46

elixir-nats

Elixir NATS client
Elixir
76
star
47

nats-account-server

A simple HTTP/NATS server to host JWTs for nats-server 2.0 account authentication.
Go
73
star
48

jwt

JWT tokens signed using NKeys for Ed25519 for the NATS ecosystem.
Go
71
star
49

nats.py2

A Tornado based Python 2 client for NATS
Python
62
star
50

nats-general

General NATS Information
61
star
51

spring-nats

A Spring Cloud Stream Binder for NATS
Java
58
star
52

terraform-provider-jetstream

Terraform Provider to manage NATS JetStream
Go
54
star
53

nats.cr

Crystal client for NATS
Crystal
44
star
54

nats-streaming-docker

Official Docker image for the NATS Streaming server
Python
44
star
55

nats-rest-config-proxy

NATS REST Configuration Proxy
Go
33
star
56

nats-connector-framework

A pluggable service to bridge NATS with other technologies
Java
32
star
57

demo-minio-nats

Demo of syncing across clouds with minio
Go
27
star
58

java-nats-examples

Repo for java-nats-examples
Java
26
star
59

asyncio-nats-examples

Repo for Python Asyncio examples
Python
25
star
60

stan.rb

Ruby NATS Streaming Client
Ruby
21
star
61

nats-mq

Simple bridge between NATS streaming and MQ Series
Go
21
star
62

jetstream-leaf-nodes-demo

Go
20
star
63

go-nats

[ARCHIVED] Golang client for NATS, the cloud native messaging system.
Go
20
star
64

nats-on-a-log

Raft log replication using NATS.
Go
20
star
65

nats-replicator

Bridge to replicate NATS Subjects or Channels to NATS Subject or Channels
Go
19
star
66

nkeys.js

NKeys for JavaScript - Node.js, Browsers, and Deno.
TypeScript
18
star
67

latency-tests

Latency and Throughput Test Framework
HCL
14
star
68

nats-jms-bridge

NATS to JMS Bridge for request/reply
Java
12
star
69

nats-connector-redis

A Redis Publish/Subscribe NATS Connector
Java
12
star
70

node-nuid

A Node.js implementation of NUID
JavaScript
10
star
71

nats-java-vertx-client

Java
10
star
72

nats.swift

Swift client for NATS, the cloud native messaging system.
Swift
10
star
73

sublist

History of the original sublist
Go
9
star
74

nkeys.py

NATS Keys for Python
Python
8
star
75

nats-siddhi-demo

A NATS with Siddhi Event Processing Reference Architecture
8
star
76

node-nats-examples

Documentation samples for node-nats
JavaScript
8
star
77

jwt.js

JWT tokens signed using nkeys for Ed25519 for the NATS JavaScript ecosystem
TypeScript
7
star
78

jetstream-gh-action

Collection of JetStream related Actions for GitHub Actions
Go
7
star
79

kubecon2020

Go
7
star
80

nats-spark-connector

Scala
7
star
81

java-nats-server-runner

Run the Nats Server From your Java code.
Java
6
star
82

kotlin-nats-examples

Repo for Kotlin Nats examples.
Kotlin
6
star
83

js-nuid

TypeScript
6
star
84

ts-nats-examples

typescript nats examples
TypeScript
5
star
85

go-nats-streaming

[ARCHIVED] NATS Streaming System
Go
5
star
86

integration-tests

Repository for integration test suites of any language
Java
5
star
87

homebrew-nats-tools

Repository hosting homebrew taps for nats-io tools
Ruby
5
star
88

ts-nkeys

A public-key signature system based on Ed25519 for the NATS ecosystem in typescript for ts-nats and node-nats
TypeScript
4
star
89

nats-steampipe-plugin

Example steampipe plugin for NATS
Go
4
star
90

nkeys.rb

NATS Keys for Ruby
Ruby
4
star
91

advisories

Advisories related to the NATS project
HTML
3
star
92

kinesis-bridge

Bridge Amazon Kinesis to NATS streams.
Go
3
star
93

not.java

A reference for distributed tracing with the NATS Java client.
Java
2
star
94

deploy

Deployment for NATS
Ruby
2
star
95

nats.c.deps

C
2
star
96

stan2js

NATS Streaming to JetStream data migration tool.
Go
2
star
97

netlify-slack

Trivial redirector website
1
star
98

cliprompts

cli prompt utils
Go
1
star
99

ruby-nats-examples

Repo for Ruby Examples
Ruby
1
star
100

nats-mendix

CSS
1
star