{"id":13765778,"url":"https://github.com/processone/rtb","last_synced_at":"2025-10-14T01:40:04.885Z","repository":{"id":136895276,"uuid":"139982351","full_name":"processone/rtb","owner":"processone","description":"Benchmarking tool to stress real-time protocols","archived":false,"fork":false,"pushed_at":"2023-12-04T16:03:59.000Z","size":418,"stargazers_count":50,"open_issues_count":4,"forks_count":7,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-06-15T10:09:19.820Z","etag":null,"topics":["benchmark","benchmarking","erlang","jabber","mqtt","real-time","realtime","websocket","xmpp"],"latest_commit_sha":null,"homepage":"https://www.process-one.net/","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/processone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-06T12:30:55.000Z","updated_at":"2024-04-10T13:01:18.000Z","dependencies_parsed_at":"2024-08-03T16:04:09.848Z","dependency_job_id":"e5e724b9-6af9-470e-8a3b-c6f39f7c2bd1","html_url":"https://github.com/processone/rtb","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/processone/rtb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Frtb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Frtb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Frtb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Frtb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/processone","download_url":"https://codeload.github.com/processone/rtb/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/processone%2Frtb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279017500,"owners_count":26086085,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["benchmark","benchmarking","erlang","jabber","mqtt","real-time","realtime","websocket","xmpp"],"created_at":"2024-08-03T16:00:45.692Z","updated_at":"2025-10-14T01:40:04.849Z","avatar_url":"https://github.com/processone.png","language":"Erlang","readme":"RTB: Benchmarking tool to stress real-time protocols\n====================================================\n![line-plot](https://raw.github.com/processone/rtb/master/img/packets-in-rate.png)\n![box-plot](https://raw.github.com/processone/rtb/master/img/ping-rtt.png)\n\nThe idea of RTB is to provide a benchmarking tool to stress test\nXMPP and MQTT servers with the minimum configuration overhead.\nAlso, at least in the XMPP world, a \"golden standard\" benchmark\nis highly demanded in order to compare server implementations,\navoiding disambiguations as much as possible. RTB is believed\nto be used in such role because it has sane defaults (gathered\nfrom statistics of real world servers) and it is able to\nstress test all features defined in the\n[XMPP Compliance Suite 2019](https://xmpp.org/extensions/xep-0412.html)\n\n**Table of Contents**:\n1. [Status](#status)\n2. [System requirements](#system-requirements)\n3. [Compiling](#compiling)\n4. [Usage](#usage)\n5. [Database population](#database-population)\n   1. [XMPP scenario](#xmpp-scenario)\n   2. [MQTT scenario](#mqtt-scenario)\n6. [Configuration](#configuration)\n   1. [General parameters](#general-parameters)\n   2. [Parameters of the XMPP scenario](#parameters-of-the-xmpp-scenario)\n   3. [Parameters of the MQTT scenario](#parameters-of-the-mqtt-scenario)\n   4. [Patterns](#patterns)\n\n# Status\n\nRTB is in an early stage of development with the following limitations:\n- MQTT support is limited to versions 3.1.1 and 5.0\n- For XMPP protocol, support for\n  [Personal Eventing Protocol](https://xmpp.org/extensions/xep-0163.html)\n  is lacking.\n\nAlso, \"sane\" defaults and what should be considered a\n\"golden benchmark\" is yet to be discussed within the XMPP and MQTT community.\n\nHowever, the tool has been already battle-tested:\n[ProcessOne](https://www.process-one.net/) is using the tool to\nstress test [ejabberd SaaS](https://ejabberd-saas.com/) deployments.\n\n# System requirements\n\nTo compile RTB you need:\n\n - Unix-like OS. Windows is not supported. Only Linux is tested.\n - GNU Make.\n - GCC\n - G++\n - Libexpat ≥ 1.95\n - Libyaml ≥ 0.1.4\n - Erlang/OTP ≥ 19.0\n - OpenSSL ≥ 1.0.0\n - Zlib ≥ 1.2.3\n - gnuplot ≥ 4.4\n\nFor Debian based distros to install all the dependencies run:\n```\n# apt install gcc g++ make libexpat1-dev libyaml-dev libssl-dev \\\n              zlib1g-dev gnuplot-nox erlang-nox erlang-dev\n```\nFor Arch Linux:\n```\n# pacman -S expat libyaml erlang-nox gnuplot\n```\nFor other Linux distros, *BSD and OSX:\n\n**TODO**: Please create an issue/PR if you know the sequence of packages to install.\n\n# Compiling\n\nAs usual, the following commands are used to obtain and compile the tool:\n```\n$ git clone https://github.com/processone/rtb.git\n$ cd rtb\n$ make\n```\n\n# Usage\n\nOnce compiled, you will find `rtb.sh`, `rtb.yml.xmpp.example` and\n`rtb.yml.mqtt.example` files. Copy either `rtb.yml.mqtt.example` or\n`rtb.yml.xmpp.example` to `rtb.yml`, edit it (see section below) and run:\n```\n$ cp rtb.yml.xmpp.example rtb.yml\n$ editor rtb.yml\n$ ./rtb.sh\n```\nInvestigate the output of the script for presence of errors. All errors\nare supposed to be self-explanatory and most of them have some hints on\nwhat should be done to fix them.\n\nTo stop the benchmark press `Ctrl+C+C`. In order to start the\nbenchmark in background append `-detached` switch:\n```\n$ ./rtb.sh -detached\n```\nYou will find logs in the `log` directory. To monitor the progress\nopen the statistics web page: it's located at `http://this.machine.tld:8080`\nby default. Edit `www_port` option to change the port if needed.\n\n# Database population\n\nDuring compilation a special utility is created which aims to help\nyou populating the server's database. It's located at `priv/bin/rtb_db`.\nRun `priv/bin/rtb_db --help` to see available options.\n\n## XMPP scenario\n\nThe utility is able to generate files for users and rosters in either\nCSV format ([ejabberd](https://www.ejabberd.im/) and [jackal](https://github.com/ortuman/jackal))\nor in Lua format ([Metronome](https://metronome.im/)/[Prosody](https://prosody.im/)).\nIn order to generate files for ejabberd execute something like:\n```\n$ priv/bin/rtb_db -t ejabberd -c 1000 -u user%@domain.tld -p pass% -r 20\n```\nThe same, but for Metronome will look like:\n```\n$ priv/bin/rtb_db -t metronome -c 1000 -u user%@domain.tld -p pass% -r 20\n\n```\nFor Prosody:\n```\n$ priv/bin/rtb_db -t prosody -c 1000 -u user%@domain.tld -p pass% -r 20\n\n```\nFor jackal:\n```\n$ priv/bin/rtb_db -t jackal -c 1000 -u user%@domain.tld -p pass% -r 20\n\n```\nHere 1000 is the total amount of users (must match `capacity` parameter\nof the configuration file) and 20 is the number of items in rosters.\nDon't provide `-r` option or set it to zero (0) if you don't want to\ngenerate rosters.\n\nFollow the hint provided by the utility to load generated files\ninto the server's spool/database. Note that `--username` and\n`--password` arguments must match those defined in the configuration file\n(see `jid` and `password` parameters).\n\n## MQTT scenario\n\nThe utility is also able to generate `passwd` file for\n[Mosquitto](https://mosquitto.org/).\nIn order to generate the file execute something like:\n```\n$ priv/bin/rtb_db -t mosquitto -c 1000 -u user% -p pass%\n```\nHere 1000 is the total amount of users (must match `capacity` parameter\nof the configuration file).\n\nFollow the hint provided by the utility to set up `passwd` file in Mosquitto\nconfiguration.\n\nNote that `--username` and `--password` arguments must match those defined\nin the configuration file (see `username` and `password` parameters).\n\n# Configuration\n\nAll configuration is performed via editing parameters of `rtb.yml` file.\nThe file has [YAML](http://en.wikipedia.org/wiki/YAML) syntax.\nThere are mandatory and optional parameters.\nThe majority of parameters are optional.\n\n## General parameters\n\nThis group of parameters are common for all scenarios.\n\n### Mandatory parameters\n\n- **scenario**: `string()`\n\n  The benchmarking scenario to use. Available values are `mqtt` and `xmpp`.\n\n- **interval**: `non_neg_integer()`\n\n  The option is used to set a timeout to wait before spawning\n  the next connection. The value is in **milliseconds**.\n\n- **capacity**: `pos_integer()`\n\n  The total amount of connections to be spawned, starting from 1.\n\n- **certfile**: `string()`\n\n  A path to a certificate file. The file MUST contain both a full certficate\n  chain and a private key in PEM format.\n\n  The option is only mandatory in the case when your scenario is configured\n  to utilize TLS connections.\n\n- **servers**: `[uri()]`\n\n  The list of server URIs to connect. The format of the URI must be\n  `scheme://hostname:port/path` where `scheme` can be `tcp`, `tls`, `ws` or `wss`;\n  `hostname` can be any DNS name or IP address and `port` is a port number.\n  Note that `scheme`, `hostname` and `port` parts of the URI are mandatory, where\n  `path` part is optional and only meaningful when the scheme is `ws` or `wss`.\n  IPv6 addresses MUST be enclosed in square brackets.\n  It's highly recommended to use IP addresses in `hostname`\n  part: excessive DNS lookups may create significant overhead for the\n  benchmarking tool itself.\n\n  The option is used to set a transport, address and port of the server(s)\n  being tested.\n\n  The option is only mandatory for MQTT scenario, because there are no well\n  established mechanisms to locate MQTT servers.\n\n  For XMPP scenario the default is empty list which means server endpoints\n  will be located according to RFC6120 procedure, that is DNS A/AAAA/SRV lookup\n  of a domain part of `jid` parameter.\n  Leaving the default alone is also not recommended for the reason described above.\n\n  An URI from the `servers` list is picked in round-robin manner during\n  initial connections setup, but it's picked randomly for reconnection attempts.\n\n  Note that WebSockets connections are currently supported by MQTT scenario only.\n\nExample:\n```yaml\nscenario: mqtt\ninterval: 10\ncapacity: 10000\ncertfile: cert.pem\nservers:\n  - tls://127.0.0.1:8883\n  - tcp://192.168.1.1:1883\n  - wss://[::1]:443/mqtt\n```\n\n### Optional parameters\n\n- **bind**: `[ip_address()]`\n\n  The list of IP addresses of local interfaces to bind. The typical\n  usage of the option is to set several binding interfaces in order\n  to establish more than 64k outgoing connections from the same machine.\n  The default is empty list: in this case a binding address will be chosen\n  automatically by the OS.\n\n- **stats_dir**: `string()`\n\n  A path to the directory where statistics data will be stored.\n  The files in the directory are used by `gnuplot` to generate statistics graphs.\n  The default value is `stats`.\n\n- **www_dir**: `string()`\n\n  A path to a directory where HTML and image files will be created.\n  The default is `www`. This is used by the statistics web interface.\n\n- **www_port**: `pos_integer()`\n\n  A port number to start the statistics web interface at. The default is 8080.\n\n- **gnuplot**: `string()`\n\n  The path to a gnuplot execution binary. By default RTB is trying to detect\n  the location of gnuplot automatically.\n\n- **debug**: `true | false`\n\n  Whether to log debug messages or not. This is only needed to track down\n  issues of the server or the tool itself. **DON'T** enable in large scale benchmarking.\n  The default is `false`.\n\nExample:\n```yaml\nbind:\n  - 192.168.1.1\n  - 192.168.1.2\n  - 192.168.1.3\nstats_dir: /tmp/rtb/stats\nwww_dir: /tmp/rtb/www\nwww_port: 1234\ngnuplot: /opt/bin/gnuplot\n```\n\n## Parameters of the XMPP scenario\n\nThis group of parameters are specific to the XMPP scenario only.\nThe parameters described here are applied per single session.\n\n### Mandatory parameters\n\n- **jid**: `pattern()`\n\n  A pattern for an XMPP address: bare or full. If it's bare, the default\n  `rtb` resource will be used. Refer to [Patterns](#patterns) section for\n  the detailed explanation of possible pattern values.\n\n- **password**: `pattern()`\n\n  The pattern for a password. Refer to [Patterns](#patterns) section for\n  the detailed explanation of possible pattern values.\n\nExample:\n```yaml\njid: user%@domain.tld\npassword: pass%\n```\n\n### Optional parameters\n\n#### Parameters for timings control.\n\n- **negotiation_timeout**: `pos_integer() | false`\n\n  A timeout to wait for a stream negotiation to complete.\n  The value is in **seconds**. It can be set to `false` to disable timeout.\n  The default is 100 seconds.\n\n- **connect_timeout**: `pos_integer() | false`\n\n  A timeout to wait for a TCP connection to be established.\n  The value is in **seconds**. It can be set to `false` to disable timeout.\n  The default is 100 seconds.\n\n- **reconnect_interval**: `pos_integer() | false`\n\n  A timeout to wait before another reconnection attempt after previous\n  connection failure. Initially it is picked randomly between `1` and this\n  configured value. Then, exponential back off is applied between several\n  consecutive connection failures. The value is in **seconds**.\n  It can be set to `false` to disable reconnection attempts completely:\n  thus the failed session will never be restored.\n  The default is 60 (1 minute) - the value recommended by\n  [RFC6120](https://tools.ietf.org/html/rfc6120#section-3.3).\n\n- **message_interval**: `pos_integer() | false`\n\n  An interval between sending messages. The value is in **seconds**.\n  It can be set to `false` to disable sending messages completely.\n  The default is 600 (10 minutes). See also `message_body_size` option.\n\n- **muc_message_interval**: `pos_integer() | false`\n\n  An interval between sending groupchat messages. The value is in **seconds**.\n  It can be set to `false` to disable sending groupchat messages completely.\n  The default is 600 (10 minutes). If there are several MUC rooms configured,\n  the groupchat message is sent to a randomly chosen one, i.e. RTB doesn't\n  multicast the message to all joined rooms.\n  See also `message_body_size` and `muc_rooms` options.\n  The option doesn't have any effect if `muc_rooms` option is not set.\n\n- **presence_interval**: `pos_integer() | false`\n\n  An interval between sending presence broadcats. The value is in **seconds**.\n  It can be set to `false` to disable sending presences completely.\n  The default is 600 (10 minutes). Note that at the first successful login a\n  presence broadcast is always sent unless the value is not set to `false`.\n\n- **disconnect_interval**: `pos_integer() | false`\n\n  An interval to wait before forcing disconnect. The value is in **seconds**.\n  The default is 600 (10 minutes). If stream management is enabled\n  (this is the default, see `sm` option), then the session\n  will be resumed after a random timeout between 1 and the value of\n  `max` attribute of `\u003cenabled/\u003e` element reported by the server.\n  Otherwise, the next reconnection attempt will be performed according\n  to the value and logic of `reconnect_interval`.\n\n- **proxy65_interval**: `pos_integer() | false`\n\n  An interval between file transfers via Proxy65 service (XEP-0065).\n  The value is in **seconds**. It can be set to `false` to disable\n  file transfer completely. The default is 600 (10 minutes).\n  See also `proxy65_size` option.\n\n- **http_upload_interval**: `pos_integer() | false`\n\n  An interval between file uploads via HTTP Upload service (XEP-0363).\n  The value is in **seconds**. It can be set to `false` to disable\n  file uploads completely. The default is 600 (10 minutes).\n  See also `http_upload_size` option.\n\n#### Parameters for payload/size control\n\n- **message_to**: `pattern()`\n\n  The pattern of a JID to which messages will be sent. By default\n  a random JID within benchmark capacity is picked (whether it is\n  already connected or not). Refer to [Patterns](#patterns) section for\n  the detailed explanation of possible pattern values.\n\n  For example, to send messages to already connected JIDs, set:\n  ```yaml\n    message_to: user?@domain.tld\n  ```\n\n- **message_body_size**: `non_neg_integer()`\n\n  The size of `\u003cbody/\u003e` element of a message in **bytes**.\n  Only makes sense when `message_interval` is not set to `false`.\n  The default is 100 bytes.\n\n- **proxy65_size**: `non_neg_integer()`\n\n  The size of a file to transfer via Proxy65 service in **bytes**.\n  Only makes sense when `proxy65_interval` is not set to `false`.\n  The default is 10485760 (10 megabytes).\n\n- **http_upload_size**: `non_neg_integer()`\n\n  The size of a file to upload via HTTP Upload service in **bytes**.\n  Only makes sense when `http_upload_interval` is not set to `false`.\n  There is no default value: the option is only needed to set\n  if the service doesn't report its maximum file size.\n\n- **mam_size**: `non_neg_integer()`\n\n  The size of the MAM archive to request from the server. Only makes\n  sense when `mam` is not set to `false`. The default is 50 (messages).\n\n- **muc_mam_size**: `non_neg_integer()`\n\n  The size of the MAM archive to request from MUC rooms. Only makes\n  sense when `muc_mam` is not set to `false`. The default is 50 (messages).\n\n#### Parameters for enabling/disabling features\n\n- **starttls**: `true | false`\n\n  Whether to use STARTTLS or not. The default is `true`.\n\n- **csi**: `true | false`\n\n  Whether to send client state indications or not (XEP-0352).\n  The default is `true`.\n\n- **sm**: `true | false`\n\n  Whether to enable stream management with resumption or not (XEP-0198).\n  The default is `true`.\n\n- **mam**: `true | false`\n\n  Whether to enable MAM and request MAM archives at login time or not (XEP-0313).\n  The default is `true`. The requested size of the archive is controlled\n  by `mam_size` option.\n\n- **muc_mam**: `true | false`\n\n  Whether to request MAM archives from MUC room or not (XEP-0313).\n  The default is `true`. The requested size of the archive is controlled\n  by `muc_mam_size` option.\n\n- **carbons**: `true | false`\n\n  Whether to enable message carbons or not (XEP-0280). The default is `true`.\n\n- **blocklist**: `true | false`\n\n  Whether to request block list at login time or not (XEP-0191).\n  The default is `true`.\n\n- **roster**: `true | false`\n\n  Whether to request roster at login time or not. The default is `true`.\n\n- **rosterver**: `true | false`\n\n  Whether to set a roster version attribute in roster request or not.\n  The default is `true`.\n\n- **private**: `true | false`\n\n  Whether to request bookmarks from private storage at login time or not (XEP-0049).\n  The default is `true`.\n\n#### Miscellaneous parameters\n\n- **muc_rooms**: `[pattern()]`\n\n  A list of MUC room bare JIDs to join, expressed as a pattern. Refer to\n  [Patterns](#patterns) section for the detailed explanation of possible pattern values.\n  The default value is an empty list which means no rooms will be joined.\n  Example:\n  ```yaml\n  muc_rooms:\n    - large1@conference.domain.tld\n    - medium[1..10]@conference.domain.tld\n    - small[1..100]@conference.domain.tld\n  ```\n\n- **sasl_mechanisms**: `[string()]`\n\n  A list of SASL mechanisms to use for authentication. Supported mechanisms are\n  `PLAIN` and `EXTERNAL`. The appropriate mechanism will be picked automatically.\n  If several mechanisms found matching then all of them will be tried in the order\n  defined by the value until the authentication is succeed. The default is `[PLAIN]`.\n  Note that for `EXTERNAL` authentication you need to have a valid certificate file\n  defined in the `certfile` option.\n\nExample:\n```yaml\nsasl_mechanisms:\n  - PLAIN\n  - EXTERNAL\n```\n\n## Parameters of the MQTT scenario\n\nThis group of parameters are specific to the MQTT scenario only.\nThe parameters described here are applied per single session.\n\n### Mandatory parameters\n\n- **client_id**: `pattern()`\n\n  A pattern for an MQTT Client ID. Refer to [Patterns](#patterns) section for\n  the detailed explanation of possible pattern values.\n\nExample:\n```yaml\nclient_id: rtb%\n```\n\n### Optional parameters\n\n#### Authentication parameters\n\n- **username**: `pattern()`\n\n  A pattern for a user name. Refer to [Patterns](#patterns) section for\n  the detailed explanation of possible pattern values.\n\n- **password**: `pattern()`\n\n  The pattern for a password. Refer to [Patterns](#patterns) section for\n  the detailed explanation of possible pattern values.\n\nExample:\n```yaml\nusername: user%\npassword: pass%\n```\n\n#### Parameters for session control\n\n- **protocol_version**: `string()`\n\n  MQTT protocol version. Can be `3.1.1` or `5.0`. The default is `3.1.1`.\n\n- **clean_session**: `true | false`\n\n  Whether to set `CleanSession` flag or not. If the value is `true` then\n  the MQTT session state (subscriptions and message queue) won't be kept\n  at the server between client reconnections and, thus, no state synchronization\n  will be performed when the session is re-established. The default is `false`.\n\n- **will**: `publish_options()`\n\n  The format of a Client Will. The parameter consists of a list of publish\n  options. See `publish` parameter description. The default is empty will.\n\nExample:\n```yaml\nprotocol_version: 5.0\nclean_session: true\nwill:\n  qos: 2\n  retain: false\n  topic: /rtb/?\n  message: \"*\"\n```\n\n#### Parameters for PUBLISH/SUBSCRIBE\n\n- **publish**: `publish_options()`\n\n  The format of a PUBLISH message. Only makes sense when `publish_interval` is\n  not set to `false`. The format is described by a group of sub-options:\n\n  - **qos**: `0..2`\n\n    Quality of Service. The default is 0.\n\n  - **retain**: `true | false`\n\n    Whether the message should be retained or not. The default is `false`.\n\n  - **topic**: `pattern()`\n\n    The pattern for a topic. Refer to [Patterns](#patterns) section for\n    the detailed explanation of possible pattern values.\n\n  - **message**: `pattern() | non_neg_integer()`\n\n    The pattern or the size of a message payload. If it's an integer\n    then the payload of the given size will be randomly generated every time\n    a message is about to be sent. Refer to [Patterns](#patterns) section for\n    the detailed explanation of possible pattern values.\n\n  Example:\n  ```yaml\n    publish:\n      qos: 1\n      retain: true\n      topic: /rtb/?\n      message: 32\n  ```\n- **subscribe**: `[{pattern(), 0..2}]`\n\n  The format of a SUBSCRIBE message. It is represented as a list of\n  topic-filter/QoS pairs. Refer to [Patterns](#patterns) section\n  for the detailed explanation of possible pattern values. The message is sent\n  immediately after successful authentication of a newly created session.\n  The default is empty list, i.e. no SUBSCRIBE messages will be sent.\n\n  Example:\n  ```yaml\n    subscribe:\n      /foo/bar/%: 2\n      $SYS/#: 1\n      /rtb/[1..10]: 0\n   ```\n\n- **track_publish_delivery**: `true | false`\n\n  Check if PUBLISH packets reach at least a single destination client. The result\n  is displayed as `publish-loss` graph in the Web statistics interface.\n  The default is `false`.\n\n  **NOTE**: the option is only available for MQTT 5.0. See `protocol_version` option.\n\n#### Parameters for timings control\n\n- **keep_alive**: `pos_integer()`\n\n  The interval to send keep-alive pings. The value is in **seconds**.\n  The default is 60 (seconds).\n\n- **reconnect_interval**: `pos_integer() | false`\n\n  A timeout to wait before another reconnection attempt after previous\n  connection failure. Initially it is picked randomly between `1` and this\n  configured value. Then, exponential back off is applied between several\n  consecutive connection failures. The value is in **seconds**.\n  It can be set to `false` to disable reconnection attempts completely:\n  thus the failed session will never be restored.\n  The default is 60 (1 minute).\n\n- **disconnect_interval**: `pos_integer() | false`\n\n  An interval to wait before forcing disconnect. The value is in **seconds**.\n  The default is 600 (10 minutes). The next reconnection attempt will be\n  performed according to the value and logic of `reconnect_interval`.\n\n- **publish_interval**: `pos_integer() | false`\n\n  An interval between sending PUBLISH messages. Can be set to `false` in order\n  to disable sending PUBLISH messages completely. The value is in **seconds**.\n  The default is 600 (10 minutes).\n\n## Patterns\n\nMany configuration options allow to set patterns as their values. The pattern\nis just a regular string with a special treatment of symbols `%`, `*`, `?`,\n`[` and `]`.\n\n### Current connection identifier\n\nThe symbol '%' is replaced by the current identifier of the connection. For example,\nwhen the pattern of `username` parameter is `user%` and the value of `capacity`\nis 5, then the value of `username` will be evaluated into `user1` for first\nconnection (i.e. the connection with identifier 1), `user2` for the second\nconnection and `user5` for the last connection.\nPatterns with such identifier are supposed to address a connection within\nwhich this pattern is evaluated.\n\nExample:\n```yaml\njid: user%@domain.tld\nclient_id: client%\npassword: pass%\n```\n\n### Random session identifier\n\nThe symbol '?' is replaced by an identifier of random available session.\nFor example, when there are already spawned 5 connections with 1,3 and 5\nconnections being fully established (and, thus, internally registered as a \"session\"),\nthe pattern `user?` will yield into `user1`, `user3` or `user5`,\nbut not into `user2` or `user4`.\nPatterns with such identifier are supposed to be used for sending/publishing\nmessages to online users.\n\nExample:\n```yaml\nmessage_to: user?@domain.tld\npublish:\n  ...\n  topic: /rtb/topic?\n  ...\n```\n\n### Unique identifier\n\nThe symbol '*' is replaced by a positive integer. The integer is guaranteed\nto be unique within the benchmark lifetime. Note that the integer is **not**\nguaranteed to be monotonic.\nPatterns with such identifiers are supposed to be used to mark some content\nas unique for further tracking (in logs or network dump).\n\nExample:\n```yaml\npublish:\n  topic: /foo/bar\n  ...\n  message: \"*\"\n```\n\n### Range identifier\n\nThe expression `[X..Y]` where `X` and `Y` are non-negative integers and `X ≤ Y`\nis replaced by a random integer between `X` and `Y` (inclusively).\nPatterns with such expression are supposed to be used for sending/publishing/subscribing\nto a restricted subset of recipients or topics.\n\nExample:\n```yaml\nsubscribe:\n  /rtb/topic/[1..10]: 2\npublish:\n  topic: /rtb/topic/[1..10]\nmuc_rooms:\n  - room[1..5]@conference.domain.tld\n```\n","funding_links":[],"categories":["Tools"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprocessone%2Frtb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprocessone%2Frtb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprocessone%2Frtb/lists"}