{"id":13728086,"url":"https://github.com/ably/ably-boomer","last_synced_at":"2025-04-30T13:43:07.465Z","repository":{"id":46294973,"uuid":"273441608","full_name":"ably/ably-boomer","owner":"ably","description":"Ably load generator for locust","archived":false,"fork":false,"pushed_at":"2023-02-14T16:27:27.000Z","size":7711,"stargazers_count":8,"open_issues_count":1,"forks_count":4,"subscribers_count":23,"default_branch":"main","last_synced_at":"2025-04-30T13:43:07.223Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ably.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-06-19T08:16:04.000Z","updated_at":"2024-02-27T01:15:12.000Z","dependencies_parsed_at":"2024-01-07T16:32:07.101Z","dependency_job_id":"ecbe3793-0e9c-483e-b48a-24de65168241","html_url":"https://github.com/ably/ably-boomer","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fably-boomer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fably-boomer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fably-boomer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ably%2Fably-boomer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ably","download_url":"https://codeload.github.com/ably/ably-boomer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251713871,"owners_count":21631616,"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","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":[],"created_at":"2024-08-03T02:00:37.054Z","updated_at":"2025-04-30T13:43:07.409Z","avatar_url":"https://github.com/ably.png","language":"Go","funding_links":[],"categories":["Tools \u0026 Integrations"],"sub_categories":["Workers"],"readme":"# ablyboomer\n\nablyboomer is an Ably load generator for Locust written in Go, based on the [boomer](https://github.com/myzhan/boomer) library.\n\nablyboomer defines a worker that performs the same function as a [Locust worker](https://docs.locust.io/en/stable/running-locust-distributed.html) in a distributed load test. It receives start and stop events from the Locust master, spawns the appropriate amount of users that subscribe, publish and enter Ably channels based on how ablyboomer is configured, and reports message delivery and latency statistics back to the master.\n\n## Quick Start\n\nFollow these steps to run a simple fanout load test against the Ably service:\n\n- Build the Docker image:\n\n```\nmake image\n```\n\n- Copy `.env.example` to `.env` to store your private environment variables:\n\n```\ncp .env.example .env\n```\n\n- Set `ABLY_API_KEY` in `.env` to your Ably app key\n\n- Start the docker-compose cluster in `examples/fanout`:\n\n```\ncd examples/fanout\ndocker-compose up\n```\n\n- Visit http://localhost:8089 in your browser and start a load test with 50 users spawning at 5 users/sec\n\nYou are now running 5 ablyboomer workers that each have 10 users subscribed to a `fanout` channel, and also\nhave a single standalone worker publishing a message to the `fanout` channel every 1s, with message latency\nvisible in the Locust web interface.\n\n## Building\n\nTo build ablyboomer as a local binary, run:\n\n```\nmake build\n```\n\nThis builds a binary at `bin/ably-boomer` that you can run directly:\n\n```\nbin/ably-boomer --help\n```\n\nYou can also build an ablyboomer Docker image with:\n\n```\nmake image\n```\n\nWhich is tagged as `ablyrealtime/ably-boomer:latest` and can be run like the binary:\n\n```\ndocker run --rm ablyrealtime/ably-boomer:latest --help\n```\n\n## Config\n\nablyboomer can be configured either using CLI flags, environment variables or a YAML config file, with\nprecedence going from config file -\u003e environment variables -\u003e CLI flags.\n\nThe path to the YAML config file defaults to `ably-boomer.yaml` in the current directory but can be set\nexplicitly with the `--config` CLI flag:\n\n```\nbin/ably-boomer --config my-config.yaml\n```\n\nAn example YAML config file for a fanout subscriber load test:\n\n```yaml\nlocust.host: locust.example.com\nsubscriber.enabled: true\nsubscriber.channels: fanout\n```\n\nOr for a standalone publisher that doesn't connect to Locust but just publishes messages to the fanout channel:\n\n```yaml\nstandalone.enabled: true\nstandalone.users: 1\nstandalone.spawn-rate: 1.0\npublisher.enabled: true\npublisher.channels: fanout\npublisher.publish-interval: 1s\n```\n\nSee `bin/ably-boomer --help` for a full list of config options.\n\n### User Numbering\n\nWhen running more than one ablyboomer process, Redis can be used to assign a unique number to each user\nin the load test. For example, with Redis enabled, if you have 5 workers that each start 10 users, they\nwill use Redis to assign numbers 1-10, 11-20, 21-30, 31-40 and 41-50.\n\nRedis can be configured with:\n\n```yaml\nredis.enable: true\nredis.addr: redis-host:6379\nredis.connect-timeout: 5s\n```\n\n### Channel Config\n\nThe `subscriber.channels`, `publisher.channels` and `presence.channels` config options are a comma separated\nlist of channels that a user should subscribe to, publish to or enter respectively.\n\nThese config options can include a Go template to dynamically render the names of the channels, with all the\n[built-in functions](https://golang.org/pkg/text/template/#hdr-Functions) available as well as a `.UserNumber`\nvariable which is the 1-indexed number of the current user and a `mod` function which performs a modulo calculation\nbetween two integers.\n\nFor example, to generate a \"personal\" channel name that is unique to each user:\n\n```yaml\nsubscriber.channels: personal-{{ .UserNumber }}\n```\n\nOr to do the same but with left-padded zeros:\n\n```yaml\nsubscriber.channels: personal-{{ printf \"%08d\" .UserNumber }}\n```\n\nOr to generate a \"sharded\" channel name that spreads the users over a fixed set of 10 channels:\n\n```yaml\nsubscriber.channels: sharded-{{ mod .UserNumber 10 }}\n```\n\n## Examples\n\nSee the `examples` directory for some example load tests which can be run using docker-compose.\n\nEach example can be run by changing into the directory, running `docker-compose up` and visiting\nhttp://localhost:8089 in your browser:\n\n```\ncd examples/personal\n\ndocker-compose up\n\n# now visit http://localhost:8089\n```\n\n### Fanout\n\nThe fanout example simulates a single channel with a large number of subscribers.\n\nEach user creates a single subscription.\n\nA standalone publisher publishes 1 message per second.\n\n### Personal\n\nThe personal example simulates a large number of channels, each with one subscriber.\n\nEach user subscribes to a channel based on their assigned number (e.g. `personal-0042`), and publishes a message to it every second.\n\n### Sharded\n\nThe sharded example simulates a large number of subscribers, sharded over a number of channels.\n\nEach user subscribes to a channel using their assigned number modulo 5 (i.e. one of `sharded-0`, `sharded-1`, `sharded-2`, `sharded-3` or `sharded-5`).\n\nA standalone publisher publishes 1 message per second to each of the 5 sharded channels.\n\n### Composite\n\nThe composite example simulates both a personal scenario and a sharded scenario.\n\nEach user subscribes to a personal channel (e.g. `personal-0042`), publishes a message to it every second,\nand also subscribes to a sharded channel (i.e. one of `sharded-0`, `sharded-1`, `sharded-2`, `sharded-3` or `sharded-5`).\n\nA standalone publisher publishes 1 message per second to each of the 5 sharded\nchannels.\n\n### Push Fanout\n\nThe push fanout example simulates a single channel with a large number of push device subscribers.\n\nEach user registers a push device with the ablyChannel transport which publishes messages back to a channel, and subscribes to that channel to measure latency of messages pushed to it. Each user then subscribes that push device to a single fanout channel.\n\nA standalone publisher publishes 1 message per second to the fanout channel.\n\nNote that running this test requires you to [enable push\nnotifications](https://knowledge.ably.com/what-are-channel-rules-and-how-can-i-use-them-in-my-app)\non a namespace (or to enable it in the default channel rule), and add it\nto the subscriber and publisher channels config options. For example, with a namespace\ncalled `push`:\n\n```yaml\nsubscriber.channels: push:fanout\n\npublisher.channels: push:fanout\n```\n\n## Performance Options\n\nThe test can be configured to debug performance. Options are set through environment variables.\n\nVariable | Description | Default | Required\n--- | --- | --- | ---\n`PERF_CPU_PROFILE_DIR` | The directorty path to write the pprof cpu profile | n/a | no\n`PERF_CPU_S3_BUCKET` | The name of the s3 bucket to upload pprof data to | n/a | no\n\nIf uploading data to s3, the s3 client is configured through the default environment as per the\n[s3 client documentation](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html).\n\n\nThe `AWS_REGION` must be set by either specifying the `AWS_REGION` environment variable or to load the environment\nfrom the configuration by setting `AWS_SDK_LOAD_CONFIG=true`. Credentials will be retrieved from `~/.aws` and a\nprofile can be selected by setting the `AWS_PROFILE` environment variable. If not using the credentials file, the\nsettings can be provided directly through environment variables.\n\n\nVariable | Description | Default | Required\n--- | --- | --- | ---\n`AWS_REGION` | The AWS region to use, i.e. `us-west-2` | n/a | no\n`AWS_SDK_LOAD_CONFIG` | A boolean indicating that region should be read from config in `~/.aws` | n/a | no\n`AWS_PROFILE` | The aws profile to use in the shared credentials file | \"default\" | no\n`AWS_ACCESS_KEY_ID` | The AWS access key id credential to use | n/a | no\n`AWS_SECRET_ACCESS_KEY`| The AWS secret access key to use | n/a | no\n`AWS_SESSION_TOKEN` | The AWS session token to use | n/a | no\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fably%2Fably-boomer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fably%2Fably-boomer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fably%2Fably-boomer/lists"}