NATS Streaming to JetStream Migration in Operations
This example demonstrates how to perform a migration of NATS Streaming channels and subscriptions to NATS JetStream streams and consumers using the stan2js migration tool. This is a one time exercise and stan2js only needs to be run once for each set of STAN channels that require migration to JetStream streams.
Code
#!/bin/bash
set -euo pipefail
        Save connection contexts
The NATS CLI can be used to save and manage contexts which declare the server(s) to connect to as well as authentication and TLS options. For this example, we will create two contexts for the NATS and STAN servers. However, if channels and/or subscriptions need to be migrated to different accounts, then multiple contexts can be used.
echo 'Saving contexts...'
nats context save stan \
  --server $STAN_URL
nats context save nats \
  --server $NATS_URL
        Generate STAN data
To showcase the migration, three channels and subscriptions will be
used. The first channel, foo, has a max_msgs limit of 400 and
one subscription. The second channel, bar, has a max_msgs
limit of 500 and two subscriptions, one of which is a queue.
The third channel, baz, has no limits and no subscriptions.
1000 messages are published to all channels.
echo 'Generating STAN data...'
generate-stan-data \
  --context stan \
  --cluster $STAN_CLUSTER \
  --client app
        Define the migration config
Define a config file required by stan2js to declare
which channels and subscriptions are to be migrated, as well
as some associated stream and consumer options. These options
are not exhaustive since many options on streams and consumers
can be changed after the migration. Refer to the stan2js
README for the full set of options.
echo 'Creating config file...'
cat <<-EOF > config.yaml
stan: stan
nats: nats
cluster: test-cluster
client: stan2js
channels:
  foo:
    stream:
      name: FOO
      replicas: 1
  bar:
    stream:
      name: BAR
      max_consumers: 10
      max_bytes: 1GB
  baz:
    stream:
      name: BAZ
      max_age: 1h
clients:
  app:
    context: stan
    subscriptions:
      sub-foo:
        channel: foo
        consumer:
          name: foo
          pull: true
      
      
      sub-bar-q:
        channel: bar
        queue: q
        consumer:
          name: bar-queue
          queue: bar-queue
      sub-bar:
        channel: bar
        consumer:
          name: bar-consumer
EOF
        Run the migration!
echo 'Running migration...'
stan2js config.yaml
        Verify the migration
Since the NATS CLI supports introspecting JetStream assets, we can use it to verify that the migration was successful. Also we can inspect the streams to confirm the headers and data look correct.
echo 'Report the streams...'
nats --context nats stream report
echo 'View 3 messages from FOO...'
nats --context nats stream view FOO 3
echo 'View 3 messages from BAR...'
nats --context nats stream view BAR 3
echo 'View 3 messages from BAZ...'
nats --context nats stream view BAZ 3
echo 'Report the consumers...'
nats --context nats consumer report FOO
nats --context nats consumer report BAR
nats --context nats consumer report BAZ
        Output
Saving contexts...
NATS Configuration Context "stan"
      Server URLs: nats://stan:4222
             Path: /root/.config/nats/context/stan.json
WARNING: Shell environment overrides in place using NATS_URL
NATS Configuration Context "nats"
      Server URLs: nats://nats:4222
             Path: /root/.config/nats/context/nats.json
WARNING: Shell environment overrides in place using NATS_URL
Generating STAN data...
Creating config file...
Running migration...
╭─────────────────────────────────────────────╮
│ Channels -> Streams                         │
├────────────┬────────────────┬───────────────┤
│ NAME       │ FIRST SEQUENCE │ LAST SEQUENCE │
├────────────┼────────────────┼───────────────┤
│ bar -> BAR │ 301 -> 1       │ 1000 -> 700   │
│ baz -> BAZ │ 1 -> 1         │ 1000 -> 1000  │
│ foo -> FOO │ 501 -> 1       │ 1000 -> 500   │
╰────────────┴────────────────┴───────────────╯
╭────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Subscriptions -> Consumers                                                                             │
├────────┬───────────────────┬─────────────────────────┬────────────┬────────────────────┬───────────────┤
│ CLIENT │ CHANNEL -> STREAM │ NAME                    │ QUEUE NAME │ CONVERTED TO PULL? │ NEXT SEQUENCE │
├────────┼───────────────────┼─────────────────────────┼────────────┼────────────────────┼───────────────┤
│ app    │ bar -> BAR        │ sub-bar -> bar-consumer │            │ false              │ 701 -> 401    │
│ app    │ bar -> BAR        │ sub-bar-q -> bar-queue  │ bar-queue  │ false              │ 351 -> 51     │
│ app    │ foo -> FOO        │ sub-foo -> foo          │            │ true               │ 601 -> 101    │
╰────────┴───────────────────┴─────────────────────────┴────────────┴────────────────────┴───────────────╯
Report the streams...
Obtaining Stream stats
╭───────────────────────────────────────────────────────────────────────────────────────────╮
│                                       Stream Report                                       │
├────────┬─────────┬───────────┬───────────┬──────────┬─────────┬──────┬─────────┬──────────┤
│ Stream │ Storage │ Placement │ Consumers │ Messages │ Bytes   │ Lost │ Deleted │ Replicas │
├────────┼─────────┼───────────┼───────────┼──────────┼─────────┼──────┼─────────┼──────────┤
│ FOO    │ File    │           │ 1         │ 500      │ 85 KiB  │ 0    │ 0       │          │
│ BAR    │ File    │           │ 2         │ 700      │ 119 KiB │ 0    │ 0       │          │
│ BAZ    │ File    │           │ 0         │ 1,000    │ 170 KiB │ 0    │ 0       │          │
╰────────┴─────────┴───────────┴───────────┴──────────┴─────────┴──────┴─────────┴──────────╯
View 3 messages from FOO...
[1] Subject: foo Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Channel: foo
  Nats-Streaming-Sequence: 501
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.980419925Z
foo: 500
[2] Subject: foo Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Channel: foo
  Nats-Streaming-Sequence: 502
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.980773425Z
foo: 501
[3] Subject: foo Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Channel: foo
  Nats-Streaming-Sequence: 503
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.981072175Z
foo: 502
View 3 messages from BAR...
[1] Subject: bar Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Sequence: 301
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.886964217Z
  Nats-Streaming-Channel: bar
bar: 300
[2] Subject: bar Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.887295217Z
  Nats-Streaming-Channel: bar
  Nats-Streaming-Sequence: 302
bar: 301
[3] Subject: bar Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Channel: bar
  Nats-Streaming-Sequence: 303
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.887588425Z
bar: 302
View 3 messages from BAZ...
[1] Subject: baz Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Channel: baz
  Nats-Streaming-Sequence: 1
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.692320384Z
baz: 0
[2] Subject: baz Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Sequence: 2
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.693268425Z
  Nats-Streaming-Channel: baz
baz: 1
[3] Subject: baz Received: 2023-10-24T10:50:07Z
  Nats-Streaming-Channel: baz
  Nats-Streaming-Sequence: 3
  Nats-Streaming-Timestamp: 2023-10-24T10:50:06.694051675Z
baz: 2
Report the consumers...
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                Consumer report for FOO with 1 consumers                                 │
├──────────┬──────┬────────────┬──────────┬─────────────┬─────────────┬─────────────┬───────────┬─────────┤
│ Consumer │ Mode │ Ack Policy │ Ack Wait │ Ack Pending │ Redelivered │ Unprocessed │ Ack Floor │ Cluster │
├──────────┼──────┼────────────┼──────────┼─────────────┼─────────────┼─────────────┼───────────┼─────────┤
│ foo      │ Pull │ Explicit   │ 30.00s   │ 0           │ 0           │ 400 / 80%   │ 0         │         │
╰──────────┴──────┴────────────┴──────────┴─────────────┴─────────────┴─────────────┴───────────┴─────────╯
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                  Consumer report for BAR with 2 consumers                                   │
├──────────────┬──────┬────────────┬──────────┬─────────────┬─────────────┬─────────────┬───────────┬─────────┤
│ Consumer     │ Mode │ Ack Policy │ Ack Wait │ Ack Pending │ Redelivered │ Unprocessed │ Ack Floor │ Cluster │
├──────────────┼──────┼────────────┼──────────┼─────────────┼─────────────┼─────────────┼───────────┼─────────┤
│ bar-consumer │ Push │ Explicit   │ 30.00s   │ 0           │ 0           │ 300 / 42%   │ 0         │         │
│ bar-queue    │ Push │ Explicit   │ 30.00s   │ 0           │ 0           │ 650 / 92%   │ 0         │         │
╰──────────────┴──────┴────────────┴──────────┴─────────────┴─────────────┴─────────────┴───────────┴─────────╯
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                Consumer report for BAZ with 0 consumers                                 │
├──────────┬──────┬────────────┬──────────┬─────────────┬─────────────┬─────────────┬───────────┬─────────┤
│ Consumer │ Mode │ Ack Policy │ Ack Wait │ Ack Pending │ Redelivered │ Unprocessed │ Ack Floor │ Cluster │
├──────────┼──────┼────────────┼──────────┼─────────────┼─────────────┼─────────────┼───────────┼─────────┤
╰──────────┴──────┴────────────┴──────────┴─────────────┴─────────────┴─────────────┴───────────┴─────────╯