{"id":13764150,"url":"https://github.com/dave/blast","last_synced_at":"2025-06-13T12:37:59.893Z","repository":{"id":57480689,"uuid":"107799716","full_name":"dave/blast","owner":"dave","description":"Blast is a simple tool for API load testing and batch jobs","archived":false,"fork":false,"pushed_at":"2018-03-01T09:57:41.000Z","size":143,"stargazers_count":219,"open_issues_count":1,"forks_count":13,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-02T03:51:16.937Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dave.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-21T17:13:09.000Z","updated_at":"2025-03-31T09:39:59.000Z","dependencies_parsed_at":"2022-09-26T17:41:16.724Z","dependency_job_id":null,"html_url":"https://github.com/dave/blast","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/dave/blast","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fblast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fblast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fblast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fblast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dave","download_url":"https://codeload.github.com/dave/blast/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dave%2Fblast/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259645848,"owners_count":22889692,"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-03T15:01:16.771Z","updated_at":"2025-06-13T12:37:59.868Z","avatar_url":"https://github.com/dave.png","language":"Go","readme":"[![Build Status](https://travis-ci.org/dave/blast.svg?branch=master)](https://travis-ci.org/dave/blast) [![Go Report Card](https://goreportcard.com/badge/github.com/dave/blast)](https://goreportcard.com/report/github.com/dave/blast) [![codecov](https://codecov.io/gh/dave/blast/branch/master/graph/badge.svg)](https://codecov.io/gh/dave/blast)\n\n\n\n\n Blast\n =====\n\n * Blast makes API requests at a fixed rate.\n * The number of concurrent workers is configurable.\n * The rate may be changed interactively during execution.\n * Blast is protocol agnostic, and adding a new worker type is trivial.\n * For load testing: random data can be added to API requests.\n * For batch jobs: CSV data can be loaded from local file or GCS bucket, and successful items from previous runs are skipped.\n\n Installation\n ============\n ## Mac\n ```\n brew tap dave/blast\n brew install blast\n ```\n\n ## Linux\n See the [releases page](https://github.com/dave/blast/releases)\n\n ## From source\n ```\n go get -u github.com/dave/blast\n ```\n\n Examples\n ========\n Using the dummy worker to send at 20,000 requests per second (the dummy worker returns after a random wait, and occasionally returns errors):\n ```\n blast --rate=20000 --workers=1000 --worker-type=\"dummy\" --worker-template='{\"min\":25,\"max\":50}'\n ```\n\n Using the http worker to request Google's homepage at one request per second (warning: this is making real http requests - don't turn the rate up!):\n ```\n blast --rate=1 --worker-type=\"http\" --payload-template='{\"method\":\"GET\",\"url\":\"http://www.google.com/\"}'\n ```\n\n Status\n ======\n\n Blast prints a summary every ten seconds. While blast is running, you can hit enter for an updated\n summary, or enter a number to change the sending rate. Each time you change the rate a new column\n of metrics is created. If the worker returns a field named `status` in it's response, the values\n are summarised as rows.\n\n Here's an example of the output:\n\n ```\n Metrics\n =======\n Concurrency:      1999 / 2000 workers in use\n\n Desired rate:     (all)        10000        1000         100\n Actual rate:      2112         5354         989          100\n Avg concurrency:  1733         1976         367          37\n Duration:         00:40        00:12        00:14        00:12\n\n Total\n -----\n Started:          84525        69004        14249        1272\n Finished:         82525        67004        14249        1272\n Mean:             376.0 ms     374.8 ms     379.3 ms     377.9 ms\n 95th:             491.1 ms     488.1 ms     488.2 ms     489.6 ms\n\n 200\n ---\n Count:            79208 (96%)  64320 (96%)  13663 (96%)  1225 (96%)\n Mean:             376.2 ms     381.9 ms     374.7 ms     378.1 ms\n 95th:             487.6 ms     489.0 ms     487.2 ms     490.5 ms\n\n 404\n ---\n Count:            2467 (3%)    2002 (3%)    430 (3%)     35 (3%)\n Mean:             371.4 ms     371.0 ms     377.2 ms     358.9 ms\n 95th:             487.1 ms     487.1 ms     486.0 ms     480.4 ms\n\n 500\n ---\n Count:            853 (1%)     685 (1%)     156 (1%)     12 (1%)\n Mean:             371.2 ms     370.4 ms     374.5 ms     374.3 ms\n 95th:             487.6 ms     487.1 ms     488.2 ms     466.3 ms\n\n Current rate is 10000 requests / second. Enter a new rate or press enter to view status.\n\n Rate?\n ```\n\n Config\n ======\n Blast is configured by config file, command line flags or environment variables. The `--config` flag specifies the config file to load, and can be `json`, `yaml`, `toml` or anything else that [viper](https://github.com/spf13/viper) can read. If the config flag is omitted, blast searches for `blast-config.xxx` in the current directory, `$HOME/.config/blast/` and `/etc/blast/`.\n\n Environment variables and command line flags override config file options. Environment variables are upper case and prefixed with \"BLAST\" e.g. `BLAST_PAYLOAD_TEMPLATE`.\n\n Templates\n =========\n The `payload-template` and `worker-template` options accept values that are rendered using the Go text/template system. Variables of the form `{{ .name }}` or `{{ \"name\" }}` are replaced with data.\n\n Additionally, several simple functions are available to inject random data which is useful in load testing scenarios:\n\n * `{{ rand_int -5 5 }}` - a random integer between -5 and 5.\n * `{{ rand_float -5 5 }}` - a random float between -5 and 5.\n * `{{ rand_string 10 }}` - a random string, length 10.\n\n\nWorkers\n=======\n\nWorker is an interface that allows blast to easily be extended to support any protocol. See `main.go` for an example of how to build a command with your custom worker type.\n\nStarter and Stopper are interfaces a worker can optionally satisfy to provide initialization or finalization logic. See `httpworker` and `dummyworker` for simple examples. \n\nExamples\n========\n\nFor load testing:\n\n```yaml\nrate: 20000\nworkers: 1000\nworker-type: \"dummy\"\npayload-template:\n  method: \"POST\"\n  path: \"/foo/?id={{ rand_int 1 10000000 }}\"\nworker-template:\n  print: false\n  base: \"https://{{ .region }}.my-api.com\"\n  min: 10\n  max: 20\nworker-variants:\n  - region: \"europe-west1\"\n  - region: \"us-east1\"\n```\n\nFor bulk API tasks:\n\n```yaml\n# data would usually be the filename of a local CSV file, or an object in a GCS bucket. However, \n# for the purposes of this example, a CSV fragment is also accepted.\ndata: |\n  user_name,action\n  dave,subscribe\n  john,subscribe\n  pete,unsubscribe\n  jimmy,unsubscribe\nresume: true\nlog: \"out.log\"\nrate: 100\nworkers: 20\nworker-type: \"dummy\"\npayload-template: \n  method: \"POST\"\n  path: \"/{{ .user_name }}/{{ .action }}/{{ .type }}/\"\nworker-template:  \n  print: true\n  base: \"https://{{ .region }}.my-api.com\"\n  min: 250\n  max: 500\npayload-variants: \n  - type: \"email\"\n  - type: \"phone\"\nworker-variants: \n  - region: \"europe-west1\"\n  - region: \"us-east1\"\nlog-data:\n  - \"user_name\"\n  - \"action\"\nlog-output: \n  - \"status\"\n```\n\nConfiguration options\n=====================\n\ndata\n----\nData sets the the data file to load. If none is specified, the worker will be called repeatedly until interrupted (useful for load testing). Load a local file or stream directly from a GCS bucket with `gs://{bucket}/{filename}.csv`. Data should be in csv format, and if `headers` is not specified the first record will be used as the headers. If a newline character is found, this string is read as the data.\n\nlog\n---\nLog sets the filename of the log file to create / append to.\n\nresume\n------\nResume instructs the tool to load the log file and skip previously successful items. Failed items will be retried.\n\nrate\n----\nRate sets the initial rate in requests per second. Simply enter a new rate during execution to adjust this. (Default: 10 requests / second).\n\nworkers\n-------\nWorkers sets the number of concurrent workers. (Default: 10 workers).\n\nworker-type\n-----------\nWorkerType sets the selected worker type. Register new worker types with the `RegisterWorkerType` method.\n\npayload-template\n----------------\nPayloadTemplate sets the template that is rendered and passed to the worker `Send` method. When setting this by command line flag or environment variable, use a json encoded string.\n\n\nAdvanced configuration options\n==============================\n\ntimeout\n-------\nTimeout sets the deadline in the context passed to the worker. Workers must respect this the context cancellation. We exit with an error if any worker is processing for timeout + 1 second. (Default: 1 second). \n\nheaders\n-------\nHeaders sets the data file headers. If omitted, the first record of the csv data source is used. When setting this by command line flag or environment variable, use a json encoded string.\n\nlog-data\n--------\nLogData sets an array of data fields to include in the output log. When setting this by command line flag or environment variable, use a json encoded string.\n\nlog-output\n----------\nLogOutput sets an array of worker response fields to include in the output log. When setting this by command line flag or environment variable, use a json encoded string.\n\nworker-template\n---------------\nWorkerTemplate sets a template to render and pass to the worker `Start` or `Stop` methods if the worker satisfies the `Starter` or `Stopper` interfaces. Use with `worker-variants` to configure several workers differently to spread load. When setting this by command line flag or environment variable, use a json encoded string.\n\nworker-variants\n---------------\nWorkerVariants sets an array of maps that will cause each worker to be initialised with different data. When setting this by command line flag or environment variable, use a json encoded string.\n\npayload-variants\n----------------\nPayloadVariants sets an array of maps that will cause each data item to be repeated with the provided data. When setting this by command line flag or environment variable, use a json encoded string.\n\nControl by code\n===============\nThe blaster package may be used to start blast from code without using the command. Here's a some \nexamples of usage:\n\n```go\nctx, cancel := context.WithCancel(context.Background())\nb := blaster.New(ctx, cancel)\ndefer b.Exit()\nb.SetWorker(func() blaster.Worker {\n\treturn \u0026blaster.ExampleWorker{\n\t\tSendFunc: func(ctx context.Context, self *blaster.ExampleWorker, in map[string]interface{}) (map[string]interface{}, error) {\n\t\t\treturn map[string]interface{}{\"status\": 200}, nil\n\t\t},\n\t}\n})\nb.Headers = []string{\"header\"}\nb.SetData(strings.NewReader(\"foo\\nbar\"))\nstats, err := b.Start(ctx)\nif err != nil {\n\tfmt.Println(err.Error())\n\treturn\n}\nfmt.Printf(\"Success == 2: %v\\n\", stats.All.Summary.Success == 2)\nfmt.Printf(\"Fail == 0: %v\", stats.All.Summary.Fail == 0)\n// Output:\n// Success == 2: true\n// Fail == 0: true\n```\n\n```go\nctx, cancel := context.WithCancel(context.Background())\nb := blaster.New(ctx, cancel)\ndefer b.Exit()\nb.SetWorker(func() blaster.Worker {\n\treturn \u0026blaster.ExampleWorker{\n\t\tSendFunc: func(ctx context.Context, self *blaster.ExampleWorker, in map[string]interface{}) (map[string]interface{}, error) {\n\t\t\treturn map[string]interface{}{\"status\": 200}, nil\n\t\t},\n\t}\n})\nb.Rate = 1000\nwg := \u0026sync.WaitGroup{}\nwg.Add(1)\ngo func() {\n\tstats, err := b.Start(ctx)\n\tif err != nil {\n\t\tfmt.Println(err.Error())\n\t\treturn\n\t}\n\tfmt.Printf(\"Success \u003e 10: %v\\n\", stats.All.Summary.Success \u003e 10)\n\tfmt.Printf(\"Fail == 0: %v\", stats.All.Summary.Fail == 0)\n\twg.Done()\n}()\n\u003c-time.After(time.Millisecond * 100)\nb.Exit()\nwg.Wait()\n// Output:\n// Success \u003e 10: true\n// Fail == 0: true\n```\n \nTo do\n=====  \n- [ ] Adjust rate automatically in response to latency? PID controller?  \n- [ ] Only use part of file: part i of j parts  \n","funding_links":[],"categories":["Software Packages","软件包","DevOps Tools","Go 工具","Go Tools"],"sub_categories":["DevOps Tools","DevOps 工具","代码分析","DevOps工具","devops 工具"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdave%2Fblast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdave%2Fblast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdave%2Fblast/lists"}