@herotel/azsb-napi-rs
v3.0.9
Published
Template project for writing node package with napi-rs
Readme
azsb-napi-rs
Node.js native binding for Azure Service Bus, implemented in Rust using
napi-rsandazservicebus.
This package provides a high-performance, async-enabled interface for interacting with Azure Service Bus queues, topics, and subscriptions directly from Node.js — powered by Rust and Tokio.
✨ Features
- 🚀 High-performance native Rust backend (Tokio + async)
- 📬 Send and receive messages to/from queues and topics
- 🔄 Subscribe to messages with thread-safe JS callbacks
- 🧩 Automatic resource management for senders and receivers
- 🧵 Graceful shutdown and async cleanup
- 🔧 Built-in retry and error handling via
BasicRetryPolicy - 🧰 x86_64-apple-darwin,aarch64-apple-darwin,x86_64-unknown-linux-gnu,x86_64-pc-windows-msvc,x86_64-unknown-linux-musl
📦 Installation
Install from npm (after publishing):
npm install azsb-napi-rsor with pnpm:
pnpm add azsb-napi-rs🚀 Quick Start
import { createAzsbClient } from "@herotel/azsb-napi-rs";
const onQueue = (err: Error | null, data: Uint8Array) => {
if (err) console.error('Queue Error:', err)
else console.log('Queue message:', Buffer.from(data).toString('utf8'))
}
const onTopic = (err: Error | null, data: Uint8Array) => {
if (err) console.error('Topic Error:', err)
else console.log('Topic message:', Buffer.from(data).toString('utf8'))
}
async function main() {
const connectionString = 'namespace connection string';
const queueName = 'queue_name';
const topicName = 'topic_name';
const subscriptionName = 'topic_subscriber_name';
const client = await createAzsbClient(connectionString);
await client.startTopicListener( onTopic , topicName, subscriptionName);
await client.startQueueListener( onQueue , queueName);
(async () => {
await client.sendMessage(queueName, "Hello 1");
await client.sendMessage(queueName, "Hello 2");
await client.sendMessage(topicName, "Hello topic");
// close one sender
await client.closeSender(queueName);
// close topic
await client.closeReceiver(topicName+'/'+subscriptionName);
// Kill everything, but nicely
await client.shutdown();
})();
}
main().catch(console.error);🧠 Architecture
Each AZSBClient maintains a set of pooled, lazily-created senders and receivers.
Multiple queues, topics, and subscriptions can share a single client.
| Scenario | Recommendation |
| --------------------------------------------------------- | -------------------------------------------------- |
| One namespace, multiple queues/topics/subscriptions | Reuse one ServiceBusClient |
| Multiple namespaces | Create a separate ServiceBusClient per namespace |
| Different retry policy, credentials, or tuning per entity | Multiple clients as needed |
| High-performance isolation | Optional multiple clients (usually unnecessary) |
⚙️ API Reference
create_azsb_client(connection_string: string) -> Promise<AZSBClient>
Creates a new client using an Azure Service Bus connection string. NOTE: Connection string must be namespace global for all queues accessed in that namespace.
AZSBClient Methods
send_message(entity_name: string, message: string) -> Promise<void>
Sends a message to the specified queue or topic.
get_queue_message(queue_name: string, timeout_secs?: number) -> Promise<Uint8Array>
Receives a single message from a queue with an optional timeout.
start_queue_listener(callback: (data: Uint8Array) => void, queue_name: string) -> Promise<void>
Starts a continuous queue listener that invokes a JS callback on each message.
start_topic_listener(callback: (data: Uint8Array) => void, topic_name: string, subscription_name: string) -> Promise<void>
Starts a listener for a topic subscription. Messages are passed to the JS callback.
close_sender(entity_name: string) -> Promise<void>
Disposes and removes a sender for a given queue or topic.
close_receiver(queue_name: string) -> Promise<void>
Disposes and removes a queue receiver.
stop_listener(name: string) -> Promise<void>
Stops a queue or topic listener by name.
shutdown() -> Promise<void>
Gracefully shuts down all senders, receivers, and listeners.
🪄 Example: Multiple Queues
const client = await create_azsb_client(process.env.AZURE_SERVICEBUS_CONNECTION_STRING!)
await client.send_message('queue1', 'Message for queue1')
await client.send_message('queue2', 'Message for queue2')
await client.start_queue_listener((msg) => {
console.log('Queue1:', Buffer.from(msg).toString())
}, 'queue1')
await client.start_queue_listener((msg) => {
console.log('Queue2:', Buffer.from(msg).toString())
}, 'queue2')🧩 Technical Notes
- Built with
napi-rs - Uses
azservicebusfor Service Bus integration - Async runtime: Tokio
- Logging: env_logger
- Threadsafe callbacks via
ThreadsafeFunctionensure non-blocking message handling
🛑 Error Handling
All async methods return a Promise.
If a Rust-side error occurs, it will surface as a JavaScript Error with a descriptive message.
Example:
try {
await client.send_message('missing-queue', 'test')
} catch (err) {
console.error('Send failed:', err)
}🧹 Cleanup
Always call client.shutdown() before exiting your app to cleanly close all senders, receivers, and listener tasks.
📄 License
© 2025 Herotel
