```js
import { ServiceBusClient } from "@azure/service-bus";
import { DefaultAzureCredential } from "@azure/identity";
const client = new ServiceBusClient(
"YOUR-NAMESPACE.servicebus.windows.net",
new DefaultAzureCredential()
);
const sender = client.createSender("[queue]");
await sender.sendMessages({ body: "hello" });
await sender.close();
await client.close();
```
JS traps:
- **Close what you open.** Every `createSender`/`createReceiver` opens an AMQP link. In a long-running service, create once and reuse; in a script, close everything or the process hangs on exit.
- **subscribe() is streaming.** For continuous processing use `receiver.subscribe({ processMessage, processError })`. For one-shot, use `receiveMessages(1, { maxWaitTimeInMs: 5000 })`.
- **Settle explicitly.** With `receiveMode: "peekLock"` (the default), you must `completeMessage`, `abandonMessage`, `deferMessage`, or `deadLetterMessage`. Unsettled messages come back after the lock expires and get reprocessed, which looks like duplicate delivery.
- **Data role.** "Azure Service Bus Data Owner" (or Sender/Receiver) at the namespace scope.
- **Error handler is required.** `subscribe` without `processError` swallows connection drops silently.
Verify: send, receive with a 5s window, complete, check the queue depth returns to zero.