aedes

repository·main·Indexed 24 days ago

https://github.com/moscajs/aedes

A barebone, high-performance, stream-based MQTT broker designed for any stream server. It is highly extensible via pluggable middlewares for persistence (e.g., MongoDB, Redis, LevelDB) and message emission (mqemitter), making it suitable for clustered, high-availability IoT backends. It supports MQTT 3.1 and 3.1.1, TCP, SSL/TLS, WebSockets, and MQTT Bridge protocol.

Tokens
9.5K
Snippets
16
Records
66
Agent score
83%

What's inside aedes

  1. Overview of Aedes features

    main

    Aedes is a barebone MQTT server that can run on any stream server. Key features include:

    • Full compatibility with MQTT 3.1 and 3.1.1
    • Standard TCP, SSL/TLS, and WebSocket support
    • Message Persistence and Automatic Reconnect
    • Offline Buffering and Backpress-support API
    • High Availability and Clusterable architecture
    • Authentication and Authorization
    • $SYS topic support
    • Pluggable middlewares
    • Dynamic Topics support
    • MQTT Bridge support between Aedes instances
  2. Prevent DoS deadlocks with drainTimeout

    main

    When publishing messages, if a client's TCP buffer is full, the broker waits for a drain event. If a client is unresponsive (e.g., slow network or crashed app), the drain event may never fire. Without a drainTimeout, a single frozen subscriber can exhaust all concurrency slots, causing a complete deadlock where no messages can be delivered to ANY client.

    Recommended settings:

    • Production: 10000 - 60000 ms.
    • High-latency networks: Higher values to avoid disconnecting legitimate slow clients.
    • Note: Setting drainTimeout: 0 disables the timeout and makes the broker vulnerable to Denial of Service (DoS) attacks.
    // Recommended for production
    const broker = await Aedes.createBroker({
      drainTimeout: 30000  // Disconnect unresponsive clients after 30 seconds
    })
    
    // Monitor disconnections
    broker.on('clientDisconnect', (client) => {
      console.log(`Client ${client.id} disconnected`)
    })
  3. Configure Aedes clusters

    main

    Aedes requires on-disk databases like MongoDB or Redis to function in a cluster. For optimal performance and stability, it is recommended to use aedes-persistence-mongodb paired with mqemitter-redis.

    To see how to implement clusters with different emitters and persistences, refer to the aedes-tests repository.

  4. Requirements for running Aedes in Clusters

    main

    To run Aedes in a clustered environment, you must use a persistence layer and an mqemitter that both support clustering.

    Tested compatible combinations include:

    • mqemitter-redis and aedes-persistence-redis
    • mqemitter-mongodb and aedes-persistence-mongodb
    • mqemitter-child-process
  5. How MQTT Bridge connections work in Aedes

    main

    Normally, Aedes consumes the retain flag from a published message and sets it to false for two reasons: to comply with MQTT 3.3.1-9 (which requires the flag to be 0 when sending to a client) and to ensure that in a cluster, only one Aedes node stores the packet.

    However, brokers connecting via the [Bridge Protocol] can propagate the retain flag as-is. When using this special protocol, subscriptions work normally, but the retain flag in the packet is preserved.

  6. Initialize an Aedes broker

    main

    You can start an Aedes broker in two ways. The recommended method is using the asynchronous static method Aedes.createBroker([options]), which creates the instance and automatically calls listen(). Alternatively, you can manually instantiate the class with new Aedes([options]) and then call await aedes.listen().

    Common configuration options include:

    • mq: Middleware for message delivery (default: mqemitter).
    • persistence: Middleware for storing QoS > 0, retained, and will packets (default: aedes-persistence).
    • concurrency: Maximum concurrent messages processed by mq (default: 100).
    • drainTimeout: Maximum time (ms) to wait for a slow client's socket to drain before disconnecting it. This is critical to prevent DoS deadlocks (default: 60000).
    • id: Unique identifier for the broker (default: uuidv4()).
  7. Run Aedes performance benchmarks

    main

    The benchmarks directory provides a suite of scripts to perform benchmark testing and reporting on Aedes. You can run the full benchmark suite, which starts an Aedes server and executes Publish/Subscribe tests for both QoS0 and QoS1, producing CSV data. This data includes the current git branch name.

    To generate a benchmark report, run the benchmark script and pipe the output to report.js via STDIN.

  8. Migrate from Aedes 0.x to 1.x

    main

    When upgrading from version 0.x to 1.x, several breaking changes must be addressed:

    1. Async/Await Persistence: The persistence interface has changed from a callback-based pattern to an async/await pattern. Ensure your persistence implementation is compatible, or Aedes will exit.
    2. Awaiting Startup: You must now await the broker startup to prevent race conditions.
    3. No Default Export: The default export has been removed to prevent behavior mixups. You must now use named imports.

    Required Persistence Versions

    To support the new async interface, you must use at least the following versions of persistence packages:

    • aedes-persistence: 10.2.2
    • aedes-persistence-level: 9.1.2
    • aedes-persistence-mongodb: 9.3.1
    • aedes-persistence-redis: 11.2.1
  9. How Aedes handles subscription updates

    main

    Aedes manages client subscriptions by tracking the state of each topic. If a client attempts to subscribe to a topic they are already subscribed to, Aedes checks if the new parameters match the existing ones:

    • qos
    • rh (retain-handling)
    • rap (retain-as-published)
    • nl (no-local)

    If any of these parameters differ from the existing subscription, Aedes will automatically perform an unsubscribe for the old configuration before applying the new subscribe request. If all parameters match, the request is ignored to avoid redundant processing.

  10. Extend broker authentication with the authenticate method

    main

    During the CONNECT sequence, Aedes calls client.broker.authenticate(client, username, password, callback). Developers can implement this method on their broker instance to provide custom authentication logic (e.g., checking a database or JWT).

    If authentication fails, the error passed to the callback should ideally include a returnCode between 2 and 5 to allow the broker to send the correct MQTT error message to the client.

  11. Understand MQTT subscription options: rh, rap, and nl

    main

    When managing subscriptions in Aedes, three specific flags control how messages are delivered to the client:

    • rh (retain-handling): Indicates how retained messages should be handled when a new subscription is created.
    • rap (retain-as-published): Indicates whether to leave the retain flag as-is (true) or to clear it before sending to subscriptions (false). The default is false.
    • nl (no-local): If set, the client will not receive its own messages (useful for preventing loops in certain architectures).