{"id":20388577,"url":"https://github.com/efureev/parallel","last_synced_at":"2026-05-04T16:40:10.335Z","repository":{"id":229205563,"uuid":"775964329","full_name":"efureev/parallel","owner":"efureev","description":null,"archived":false,"fork":false,"pushed_at":"2024-06-13T16:51:39.000Z","size":1578,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-15T09:02:36.588Z","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/efureev.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,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-22T12:02:14.000Z","updated_at":"2024-06-13T16:51:42.000Z","dependencies_parsed_at":"2024-03-22T19:25:14.048Z","dependency_job_id":"7c6c5a59-139d-4775-90e0-ffdc8788322e","html_url":"https://github.com/efureev/parallel","commit_stats":null,"previous_names":["efureev/parallel"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efureev%2Fparallel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efureev%2Fparallel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efureev%2Fparallel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/efureev%2Fparallel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/efureev","download_url":"https://codeload.github.com/efureev/parallel/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241940541,"owners_count":20045878,"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-11-15T03:11:39.597Z","updated_at":"2026-05-04T16:40:10.288Z","avatar_url":"https://github.com/efureev.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Parallel\n\n[![Go Coverage](https://github.com/efureev/parallel/wiki/coverage.svg)](https://raw.githack.com/wiki/efureev/parallel/coverage.html)\n[![Test](https://github.com/efureev/parallel/actions/workflows/test.yml/badge.svg)](https://github.com/efureev/parallel/actions/workflows/test.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/efureev/parallel)](https://goreportcard.com/report/github.com/efureev/parallel)\n\nA small CLI to run multiple console commands in parallel with readable, colored output. Useful for local development\nwhen you need to run several services/tools at once (web server, queues, bundlers, watchers, etc.).\n\nHighlights:\n\n- Parallel execution of independent chains\n- Inside a chain: non‑piped commands run sequentially; `pipe: true` commands run concurrently within the same chain\n- Human‑friendly colored logs per chain with optional streaming (`pipe`)\n- Graceful shutdown: forwards the original OS signal to the whole process group and waits\n- YAML configuration, Docker helpers, name formatting\n\nThis README includes typical use cases and practical examples.\n\n## Installation\n\nRequirements: Go 1.25+ (tested on macOS/Linux)\n\n```shell\ngo install github.com/efureev/parallel@latest\n```\n\nThe binary will be placed at `$(go env GOPATH)/bin/parallel`.\n\n## Quick start\n\nIf you have a configuration file `.parallelrc.yaml` in the working directory:\n\n```shell\nparallel\n```\n\nIf the configuration file is located elsewhere:\n\n```shell\nparallel -f /path/to/config/flow.yaml\n```\n\nFlags are supported currently:\n\n- `-f` — path to YAML config (defaults to `.parallelrc.yaml`)\n- `-v` — version info\n\n## Screenshots\n\n![screen1.png](.assets%2Fscreen1.png)\n![sceen2.png](.assets%2Fsceen2.png)\n![screen3.png](.assets%2Fscreen3.png)\n\n## Configuration (YAML)\n\nTop‑level key: `commands`. It maps chain names to command sets. Each command can be a regular OS command or a Docker\nrecipe.\n\n```yaml\ncommands: # list of parallel command chains\n  php-server: # chain name\n    artisan: # command key inside the chain\n      pipe: true                 # stream stdout/stderr\n      cmd: [ 'php', 'artisan', 'serve', '--port', '8010' ]\n      dir: 'app'                 # working directory\n\n  web-services:\n    nginx-cmd:\n      pipe: true\n      cmd: [ 'docker', 'container', 'run', '--rm', '-p', '8090:80', '--name', 'nginx', 'nginx' ]\n      format:\n        cmdName: '%CMD_NAME% %CMD_ARGS%'\n\n  docker-services: # Docker shorthand mode\n    nginx-docker:\n      docker:\n        image:\n          name: 'nginx'\n          # tag: 'v1'            # default: 'latest'\n          # pull: 'always'       # default: none\n        ports: [ '127.0.0.1:80:8080', '127.0.0.1:443:8443' ]\n        # removeAfterAll: false  # default: true\n        # cmd: 'exec'            # default: 'run'\n\n  frontend:\n    list-files:\n      cmd: [ 'ls', '-la' ]         # executed without pipe\n    yarn-dev:\n      pipe: true\n      cmd: [ 'yarn', 'dev' ]\n      dir: 'app'\n\n  network:\n    ping-test:\n      pipe: true\n      cmd: [ 'ping', '-c', '3', 'ya.ru' ]\n```\n\n### Fields\n\n- `pipe: true` — stream output live and start the command concurrently within its chain. The chain will wait for all\n  piped commands to finish before completing.\n- `pipe: false` (or missing) — run sequentially, respecting the order in the chain. Output is printed as a block after\n  the command finishes.\n- `cmd: ['bin', 'arg1', ...]` — regular command and its args.\n- `dir: 'path'` — working directory for the command.\n- `disable: true` — disable a command without removing it from config. Disabled commands are shown in the flow preview\n  and are skipped during execution. Default: `false`.\n- `format.cmdName` — display name template. Supports placeholders:\n    - `%CMD_NAME%` — command name (either `Name` or `Cmd`)\n    - `%CMD_ARGS%` — arguments joined by space\n\n### Docker mode\n\nWhen `docker` section is used, the tool builds the final `docker` command for you, adds `--rm` by default (unless\n`removeAfterAll: false`), applies `pull` policy and ports, and always runs with `pipe: true` for live logs. Because of\nthis, Docker commands start concurrently and the chain waits for them to finish.\n\nExample of disabling commands (works for both regular and docker forms):\n\n```yaml\ncommands:\n  api:\n    serve:\n      pipe: true\n      disable: true           # will be listed but not executed\n      cmd: [ 'go', 'run', './cmd/api' ]\n\n  docker-services:\n    nginx:\n      disable: true           # will be skipped\n      docker:\n        image:\n          name: nginx\n```\n\n## How it runs\n\n- Parallel starts each chain concurrently.\n- Inside a chain:\n    - Commands with `pipe: false` are executed sequentially, in order.\n    - Commands with `pipe: true` start immediately and run concurrently with others in the same chain; the chain\n      completes only after all piped commands finish.\n    - If a non‑piped command fails, subsequent commands in that chain are not started; already running piped commands\n      are awaited.\n- For `pipe: true`, stdout/stderr are streamed and colorized per chain.\n- For non‑pipe commands, output is shown as a formatted block after completion.\n\nExample of mixing piped and non‑piped commands in one chain:\n\n```yaml\ncommands:\n  api:\n    migrate:\n      cmd: [ 'go', 'run', './cmd/migrate' ] # runs sequentially while long-runner keeps streaming\n\n    long-runner:\n      pipe: true\n      cmd: [ 'go', 'run', './cmd/api' ]\n\n    health-check:\n      pipe: true                          # starts concurrently; chain will wait for it at the end\n      cmd: [ 'curl', '-s', 'http://localhost:8080/health' ]\n```\n\n## Graceful shutdown\n\nParallel traps `SIGINT`, `SIGTERM`, `SIGQUIT` and forwards the same signal to the entire process group of each running\ncommand (`setpgid` + group signal). Then it waits for completion up to a short timeout and only then force‑kills\nremaining groups.\n\nWhat this means for you:\n\n- Press Ctrl+C once to stop everything gracefully.\n- Long‑running children that handle signals (e.g., `node`, `php artisan serve`, `yarn`) can clean up before exit.\n\n## Flow preview\n\nBefore execution, the tool prints a readable breakdown of your Flow (chains and commands) so you see exactly what will\nrun. Example:\n\n```\nFlow structure:\n  Chain 1: server\n    [1] php\n        Exec : php artisan queue:work --queue=image-resizing\n        Dir  : /path/to/app\n        Pipe : true\n        Name : %CMD_NAME%\n```\n\n## Typical use cases\n\n- Web + Frontend dev:\n    - Laravel/Symfony server, queue workers, plus `yarn dev`\n    - Vite/webpack dev server together with API\n- Micro‑services demo: run several APIs + Nginx proxy in Docker\n- Background jobs: watch two queues and a scheduler simultaneously\n- Diagnostics: tail logs, run `ping`/`curl`/`watch` side by side\n\n## Examples\n\nRun with the default config in cwd:\n\n```shell\nparallel\n```\n\nRun with a custom config path:\n\n```shell\nparallel -f app/flow.yaml\n```\n\nMinimal config to run two commands in parallel:\n\n```yaml\ncommands:\n  api:\n    serve:\n      pipe: true\n      cmd: [ 'go', 'run', './cmd/api' ]\n  ui:\n    dev:\n      pipe: true\n      cmd: [ 'yarn', 'dev' ]\n      dir: 'web'\n```\n\n## Troubleshooting\n\n- Command exits immediately with no output\n    - Check `cmd` and arguments; make sure the binary exists in `PATH`\n    - Verify `dir` points to a valid folder\n- Docker command keeps running after Ctrl+C\n    - The tool sends signal to the process group; ensure your containerized process handles `SIGTERM` and stops promptly\n- YAML error: “invalid flow configuration”\n    - The tool validates that each chain has at least one command and each command has a non‑empty `cmd`\n\n## Development\n\nRun tests:\n\n```shell\ngo test ./...\n```\n\nThe project structure is split into clear layers:\n\n- file loading (`fileLoader.go`) → raw YAML\n- flow building (`flowBuilder.go`) → domain model (`Flow`)\n- validation (`Flow.Validate`)\n- output formatting (`output.go`, `flowReader.go`)\n- execution and shutdown management (`manager.go`, `process_registry.go`, `chain_executor.go`)\n\n## License\n\nMIT\n\n---\n\nРусский кратко\n\nParallel — утилита для параллельного запуска нескольких команд с читаемым цветным выводом и корректным завершением.\nКонфигурация — YAML, запуск: `parallel -f app/flow.yaml`. См. примеры выше и `app/flow.yaml`.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fefureev%2Fparallel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fefureev%2Fparallel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fefureev%2Fparallel/lists"}