biucingcli 0.9.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- biucingcli/__init__.py +5 -0
- biucingcli/cli.py +849 -0
- biucingcli/template_data/android/template/.editorconfig +9 -0
- biucingcli/template_data/android/template/.gitignore +26 -0
- biucingcli/template_data/android/template/.mise.toml +3 -0
- biucingcli/template_data/android/template/Brewfile +6 -0
- biucingcli/template_data/android/template/Makefile +103 -0
- biucingcli/template_data/android/template/README.md +163 -0
- biucingcli/template_data/android/template/app/build.gradle.kts +178 -0
- biucingcli/template_data/android/template/app/proguard-rules.pro +1 -0
- biucingcli/template_data/android/template/app/src/androidTest/java/app/HomeRouteUiTest.kt +21 -0
- biucingcli/template_data/android/template/app/src/main/AndroidManifest.xml +18 -0
- biucingcli/template_data/android/template/app/src/main/java/app/MainActivity.kt +36 -0
- biucingcli/template_data/android/template/app/src/main/res/values/strings.xml +4 -0
- biucingcli/template_data/android/template/app/src/main/res/values/themes.xml +8 -0
- biucingcli/template_data/android/template/app/src/test/java/app/AppSmokeTest.kt +19 -0
- biucingcli/template_data/android/template/build.gradle.kts +27 -0
- biucingcli/template_data/android/template/core/designsystem/build.gradle.kts +33 -0
- biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/Components.kt +75 -0
- biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/DesignTokens.kt +23 -0
- biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/Theme.kt +110 -0
- biucingcli/template_data/android/template/core/model/build.gradle.kts +26 -0
- biucingcli/template_data/android/template/core/model/src/main/java/model/Greeting.kt +6 -0
- biucingcli/template_data/android/template/core/model/src/test/java/model/GreetingTest.kt +16 -0
- biucingcli/template_data/android/template/core/network/build.gradle.kts +26 -0
- biucingcli/template_data/android/template/core/network/src/main/java/network/AppEnvironment.kt +17 -0
- biucingcli/template_data/android/template/core/testing/build.gradle.kts +27 -0
- biucingcli/template_data/android/template/core/testing/src/main/java/testing/FakeAppEnvironmentProvider.kt +13 -0
- biucingcli/template_data/android/template/docs/release-delivery.md +68 -0
- biucingcli/template_data/android/template/docs/release-signing.properties.example +20 -0
- biucingcli/template_data/android/template/fastlane/.env.example +22 -0
- biucingcli/template_data/android/template/fastlane/Appfile +1 -0
- biucingcli/template_data/android/template/fastlane/Fastfile +121 -0
- biucingcli/template_data/android/template/feature/home/build.gradle.kts +35 -0
- biucingcli/template_data/android/template/feature/home/src/main/java/home/HomeRoute.kt +38 -0
- biucingcli/template_data/android/template/feature/settings/build.gradle.kts +34 -0
- biucingcli/template_data/android/template/feature/settings/src/main/java/settings/SettingsRoute.kt +35 -0
- biucingcli/template_data/android/template/gradle/libs.versions.toml +35 -0
- biucingcli/template_data/android/template/gradle/verification-metadata.xml +3462 -0
- biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.jar +0 -0
- biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.jar.sha256 +1 -0
- biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.properties +10 -0
- biucingcli/template_data/android/template/gradle.properties +4 -0
- biucingcli/template_data/android/template/gradlew +252 -0
- biucingcli/template_data/android/template/gradlew.bat +94 -0
- biucingcli/template_data/android/template/scripts/artifact-info +11 -0
- biucingcli/template_data/android/template/scripts/bootstrap +17 -0
- biucingcli/template_data/android/template/scripts/doctor +133 -0
- biucingcli/template_data/android/template/scripts/setup-android-sdk +23 -0
- biucingcli/template_data/android/template/scripts/sync-gradle-wrapper +19 -0
- biucingcli/template_data/android/template/scripts/verify-gradle-supply-chain +61 -0
- biucingcli/template_data/android/template/scripts/verify-release-artifact +104 -0
- biucingcli/template_data/android/template/settings.gradle.kts +25 -0
- biucingcli/template_data/android/template.json +146 -0
- biucingcli/template_data/apple/template/.gitignore +28 -0
- biucingcli/template_data/apple/template/.mise.toml +4 -0
- biucingcli/template_data/apple/template/.swiftformat +10 -0
- biucingcli/template_data/apple/template/.swiftlint.yml +33 -0
- biucingcli/template_data/apple/template/App/Config/ProjectDescriptionHelpers/Module.swift +6 -0
- biucingcli/template_data/apple/template/App/Config/XCConfig/Base.xcconfig +4 -0
- biucingcli/template_data/apple/template/App/Project.swift +66 -0
- biucingcli/template_data/apple/template/App/Targets/App/Resources/.gitkeep +1 -0
- biucingcli/template_data/apple/template/App/Targets/App/Sources/AppEntry.swift +9 -0
- biucingcli/template_data/apple/template/App/Targets/App/Sources/HomeView.swift +18 -0
- biucingcli/template_data/apple/template/App/Targets/App/Sources/HomeViewModel.swift +38 -0
- biucingcli/template_data/apple/template/App/Targets/AppTests/Sources/AppTests.swift +59 -0
- biucingcli/template_data/apple/template/Brewfile +8 -0
- biucingcli/template_data/apple/template/Makefile +128 -0
- biucingcli/template_data/apple/template/Packages/AppServices/Package.swift +20 -0
- biucingcli/template_data/apple/template/Packages/AppServices/Sources/AppServices/StarterMetadata.swift +52 -0
- biucingcli/template_data/apple/template/Packages/DesignSystem/Package.swift +20 -0
- biucingcli/template_data/apple/template/Packages/DesignSystem/Sources/DesignSystem/Theme.swift +8 -0
- biucingcli/template_data/apple/template/README.md +133 -0
- biucingcli/template_data/apple/template/Tuist.swift +8 -0
- biucingcli/template_data/apple/template/Workspace.swift +11 -0
- biucingcli/template_data/apple/template/docs/release-delivery.md +55 -0
- biucingcli/template_data/apple/template/fastlane/.env.example +20 -0
- biucingcli/template_data/apple/template/fastlane/Appfile +3 -0
- biucingcli/template_data/apple/template/fastlane/Fastfile +126 -0
- biucingcli/template_data/apple/template/fastlane/Matchfile +7 -0
- biucingcli/template_data/apple/template/scripts/bootstrap +9 -0
- biucingcli/template_data/apple/template/scripts/doctor +163 -0
- biucingcli/template_data/apple/template/scripts/setup-xcode +6 -0
- biucingcli/template_data/apple/template/scripts/test-destination +42 -0
- biucingcli/template_data/apple/template/scripts/verify-release-identity +88 -0
- biucingcli/template_data/apple/template.json +110 -0
- biucingcli/template_data/frontend/template/.dockerignore +8 -0
- biucingcli/template_data/frontend/template/.env.example +1 -0
- biucingcli/template_data/frontend/template/.gitignore +7 -0
- biucingcli/template_data/frontend/template/.npmrc +1 -0
- biucingcli/template_data/frontend/template/.prettierignore +2 -0
- biucingcli/template_data/frontend/template/.prettierrc.json +4 -0
- biucingcli/template_data/frontend/template/Dockerfile +25 -0
- biucingcli/template_data/frontend/template/Dockerfile.dev +35 -0
- biucingcli/template_data/frontend/template/Dockerfile.dev.full +40 -0
- biucingcli/template_data/frontend/template/Makefile +137 -0
- biucingcli/template_data/frontend/template/README.md +146 -0
- biucingcli/template_data/frontend/template/compose.dev.yaml +29 -0
- biucingcli/template_data/frontend/template/eslint.config.js +27 -0
- biucingcli/template_data/frontend/template/index.html +12 -0
- biucingcli/template_data/frontend/template/nginx.conf +11 -0
- biucingcli/template_data/frontend/template/package.json +50 -0
- biucingcli/template_data/frontend/template/playwright.production.config.ts +21 -0
- biucingcli/template_data/frontend/template/playwright.smoke.config.ts +19 -0
- biucingcli/template_data/frontend/template/pnpm-lock.yaml +4054 -0
- biucingcli/template_data/frontend/template/public/.gitkeep +1 -0
- biucingcli/template_data/frontend/template/scripts/browser-smoke-production +55 -0
- biucingcli/template_data/frontend/template/scripts/doctor +46 -0
- biucingcli/template_data/frontend/template/src/App.test.tsx +18 -0
- biucingcli/template_data/frontend/template/src/App.tsx +5 -0
- biucingcli/template_data/frontend/template/src/components/MetricCard.tsx +14 -0
- biucingcli/template_data/frontend/template/src/components/TaskPanel.tsx +32 -0
- biucingcli/template_data/frontend/template/src/config/env.ts +3 -0
- biucingcli/template_data/frontend/template/src/hooks/useProjectOverview.ts +24 -0
- biucingcli/template_data/frontend/template/src/index.css +208 -0
- biucingcli/template_data/frontend/template/src/main.tsx +11 -0
- biucingcli/template_data/frontend/template/src/pages/HomePage.tsx +60 -0
- biucingcli/template_data/frontend/template/src/router/AppRouter.tsx +14 -0
- biucingcli/template_data/frontend/template/src/services/api/client.ts +33 -0
- biucingcli/template_data/frontend/template/src/services/projectOverview.ts +39 -0
- biucingcli/template_data/frontend/template/src/test/setup.ts +1 -0
- biucingcli/template_data/frontend/template/src/types/projectOverview.ts +22 -0
- biucingcli/template_data/frontend/template/src/vite-env.d.ts +9 -0
- biucingcli/template_data/frontend/template/tests/browser-smoke.spec.ts +16 -0
- biucingcli/template_data/frontend/template/tests/production-browser-smoke.spec.ts +22 -0
- biucingcli/template_data/frontend/template/tsconfig.json +21 -0
- biucingcli/template_data/frontend/template/vite.config.ts +12 -0
- biucingcli/template_data/frontend/template.json +81 -0
- biucingcli/template_data/harmonyos/template/.gitignore +21 -0
- biucingcli/template_data/harmonyos/template/.mise.toml +2 -0
- biucingcli/template_data/harmonyos/template/AppScope/app.json5 +10 -0
- biucingcli/template_data/harmonyos/template/AppScope/resources/base/element/string.json +8 -0
- biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/background.svg +3 -0
- biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/foreground.svg +4 -0
- biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/layered_image.json +6 -0
- biucingcli/template_data/harmonyos/template/Makefile +106 -0
- biucingcli/template_data/harmonyos/template/README.md +152 -0
- biucingcli/template_data/harmonyos/template/build-profile.json5 +36 -0
- biucingcli/template_data/harmonyos/template/code-linter.json5 +12 -0
- biucingcli/template_data/harmonyos/template/docs/release-signing.local.properties.example +14 -0
- biucingcli/template_data/harmonyos/template/entry/build-profile.json5 +9 -0
- biucingcli/template_data/harmonyos/template/entry/hvigorfile.ts +6 -0
- biucingcli/template_data/harmonyos/template/entry/oh-package.json5 +9 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/core/config/AppConfig.ets +10 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/core/designsystem/Tokens.ets +28 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/entryability/EntryAbility.ets +29 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/pages/Index.ets +47 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/ets/pages/Settings.ets +96 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/module.json5 +34 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/element/color.json +24 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/element/string.json +12 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/media/app_icon.svg +5 -0
- biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/profile/main_pages.json +6 -0
- biucingcli/template_data/harmonyos/template/entry/src/test/List.test.ets +11 -0
- biucingcli/template_data/harmonyos/template/hvigor/hvigor-config.json5 +8 -0
- biucingcli/template_data/harmonyos/template/hvigorfile.ts +6 -0
- biucingcli/template_data/harmonyos/template/oh-package-lock.json5 +19 -0
- biucingcli/template_data/harmonyos/template/oh-package.json5 +13 -0
- biucingcli/template_data/harmonyos/template/scripts/artifact-info +31 -0
- biucingcli/template_data/harmonyos/template/scripts/bootstrap +38 -0
- biucingcli/template_data/harmonyos/template/scripts/doctor +147 -0
- biucingcli/template_data/harmonyos/template/scripts/lint +105 -0
- biucingcli/template_data/harmonyos/template/scripts/release-build +199 -0
- biucingcli/template_data/harmonyos/template/scripts/release-preflight +109 -0
- biucingcli/template_data/harmonyos/template/scripts/test +28 -0
- biucingcli/template_data/harmonyos/template/scripts/verify-release-artifact +173 -0
- biucingcli/template_data/harmonyos/template/scripts/verify-supply-chain +70 -0
- biucingcli/template_data/harmonyos/template.json +134 -0
- biucingcli/template_data/microservice/template/.air.toml +11 -0
- biucingcli/template_data/microservice/template/.dockerignore +5 -0
- biucingcli/template_data/microservice/template/.gitignore +4 -0
- biucingcli/template_data/microservice/template/.mise.toml +3 -0
- biucingcli/template_data/microservice/template/Brewfile +7 -0
- biucingcli/template_data/microservice/template/Dockerfile +44 -0
- biucingcli/template_data/microservice/template/Dockerfile.dev +50 -0
- biucingcli/template_data/microservice/template/Makefile +145 -0
- biucingcli/template_data/microservice/template/README.md +191 -0
- biucingcli/template_data/microservice/template/api/buf.gen.yaml +11 -0
- biucingcli/template_data/microservice/template/api/buf.yaml +11 -0
- biucingcli/template_data/microservice/template/api/proto/service/v1/service.proto +18 -0
- biucingcli/template_data/microservice/template/cmd/server/main.go +81 -0
- biucingcli/template_data/microservice/template/compose.dev.yaml +49 -0
- biucingcli/template_data/microservice/template/configs/config.yaml +18 -0
- biucingcli/template_data/microservice/template/deploy/compose.yaml +35 -0
- biucingcli/template_data/microservice/template/deploy/otel-collector.yaml +15 -0
- biucingcli/template_data/microservice/template/go.mod +53 -0
- biucingcli/template_data/microservice/template/go.sum +138 -0
- biucingcli/template_data/microservice/template/internal/config/config.go +112 -0
- biucingcli/template_data/microservice/template/internal/config/config_test.go +92 -0
- biucingcli/template_data/microservice/template/internal/handler/health.go +25 -0
- biucingcli/template_data/microservice/template/internal/handler/ping.go +25 -0
- biucingcli/template_data/microservice/template/internal/model/health.go +8 -0
- biucingcli/template_data/microservice/template/internal/model/ping.go +7 -0
- biucingcli/template_data/microservice/template/internal/repository/.gitkeep +1 -0
- biucingcli/template_data/microservice/template/internal/router/router.go +26 -0
- biucingcli/template_data/microservice/template/internal/runtime/server.go +116 -0
- biucingcli/template_data/microservice/template/internal/runtime/server_test.go +161 -0
- biucingcli/template_data/microservice/template/internal/service/health.go +26 -0
- biucingcli/template_data/microservice/template/internal/service/ping.go +23 -0
- biucingcli/template_data/microservice/template/internal/telemetry/telemetry.go +56 -0
- biucingcli/template_data/microservice/template/internal/transport/grpc.go +51 -0
- biucingcli/template_data/microservice/template/internal/transport/ping.go +28 -0
- biucingcli/template_data/microservice/template/scripts/bootstrap +29 -0
- biucingcli/template_data/microservice/template/scripts/doctor +115 -0
- biucingcli/template_data/microservice/template/tests/server_test.go +153 -0
- biucingcli/template_data/microservice/template.json +114 -0
- biucingcli/template_data/web-service/template/.air.toml +11 -0
- biucingcli/template_data/web-service/template/.dockerignore +5 -0
- biucingcli/template_data/web-service/template/.gitignore +5 -0
- biucingcli/template_data/web-service/template/.mise.toml +2 -0
- biucingcli/template_data/web-service/template/Brewfile +5 -0
- biucingcli/template_data/web-service/template/Dockerfile +41 -0
- biucingcli/template_data/web-service/template/Dockerfile.dev +45 -0
- biucingcli/template_data/web-service/template/Makefile +113 -0
- biucingcli/template_data/web-service/template/README.md +164 -0
- biucingcli/template_data/web-service/template/cmd/server/main.go +50 -0
- biucingcli/template_data/web-service/template/compose.dev.yaml +28 -0
- biucingcli/template_data/web-service/template/compose.yaml +14 -0
- biucingcli/template_data/web-service/template/configs/config.yaml +10 -0
- biucingcli/template_data/web-service/template/go.mod +36 -0
- biucingcli/template_data/web-service/template/go.sum +89 -0
- biucingcli/template_data/web-service/template/internal/config/config.go +84 -0
- biucingcli/template_data/web-service/template/internal/config/config_test.go +88 -0
- biucingcli/template_data/web-service/template/internal/handler/health.go +25 -0
- biucingcli/template_data/web-service/template/internal/handler/ping.go +25 -0
- biucingcli/template_data/web-service/template/internal/handler/user.go +40 -0
- biucingcli/template_data/web-service/template/internal/model/health.go +6 -0
- biucingcli/template_data/web-service/template/internal/model/ping.go +7 -0
- biucingcli/template_data/web-service/template/internal/model/user.go +7 -0
- biucingcli/template_data/web-service/template/internal/repository/.gitkeep +1 -0
- biucingcli/template_data/web-service/template/internal/repository/user.go +37 -0
- biucingcli/template_data/web-service/template/internal/router/router.go +28 -0
- biucingcli/template_data/web-service/template/internal/runtime/server.go +76 -0
- biucingcli/template_data/web-service/template/internal/runtime/server_test.go +139 -0
- biucingcli/template_data/web-service/template/internal/service/health.go +22 -0
- biucingcli/template_data/web-service/template/internal/service/ping.go +23 -0
- biucingcli/template_data/web-service/template/internal/service/user.go +27 -0
- biucingcli/template_data/web-service/template/scripts/bootstrap +23 -0
- biucingcli/template_data/web-service/template/scripts/doctor +83 -0
- biucingcli/template_data/web-service/template/tests/server_test.go +160 -0
- biucingcli/template_data/web-service/template.json +88 -0
- biucingcli/template_data/worker/template/.dockerignore +3 -0
- biucingcli/template_data/worker/template/.gitignore +2 -0
- biucingcli/template_data/worker/template/.mise.toml +2 -0
- biucingcli/template_data/worker/template/Brewfile +1 -0
- biucingcli/template_data/worker/template/Dockerfile +19 -0
- biucingcli/template_data/worker/template/Dockerfile.dev +9 -0
- biucingcli/template_data/worker/template/Makefile +105 -0
- biucingcli/template_data/worker/template/README.md +164 -0
- biucingcli/template_data/worker/template/cmd/worker/main.go +41 -0
- biucingcli/template_data/worker/template/compose.dev.yaml +29 -0
- biucingcli/template_data/worker/template/configs/config.json +11 -0
- biucingcli/template_data/worker/template/go.mod +3 -0
- biucingcli/template_data/worker/template/go.sum +1 -0
- biucingcli/template_data/worker/template/internal/config/config.go +108 -0
- biucingcli/template_data/worker/template/internal/config/config_test.go +86 -0
- biucingcli/template_data/worker/template/internal/runtime/runner.go +199 -0
- biucingcli/template_data/worker/template/internal/runtime/runner_test.go +215 -0
- biucingcli/template_data/worker/template/internal/task/heartbeat.go +19 -0
- biucingcli/template_data/worker/template/scripts/bootstrap +6 -0
- biucingcli/template_data/worker/template/scripts/doctor +41 -0
- biucingcli/template_data/worker/template/tests/worker_test.go +44 -0
- biucingcli/template_data/worker/template.json +100 -0
- biucingcli/templates.py +902 -0
- biucingcli-0.9.1.dist-info/METADATA +204 -0
- biucingcli-0.9.1.dist-info/RECORD +269 -0
- biucingcli-0.9.1.dist-info/WHEEL +5 -0
- biucingcli-0.9.1.dist-info/entry_points.txt +2 -0
- biucingcli-0.9.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
APP_NAME={{WORKER_NAME}}
|
|
2
|
+
WORKTREE_ROOT ?=$(shell git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
3
|
+
WORKTREE_LABEL ?=$(shell basename "$(WORKTREE_ROOT)" | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed 's/^-//; s/-$$//')
|
|
4
|
+
WORKTREE_ID ?=$(shell printf '%s' "$(WORKTREE_ROOT)" | shasum | cut -c1-8)
|
|
5
|
+
WORKTREE_SLUG ?=$(APP_NAME)-$(WORKTREE_ID)
|
|
6
|
+
COMPOSE_PROJECT_NAME ?=$(WORKTREE_SLUG)
|
|
7
|
+
IMAGE ?=$(WORKTREE_SLUG)
|
|
8
|
+
TAG ?=dev
|
|
9
|
+
IMAGE_REF := $(IMAGE):$(TAG)
|
|
10
|
+
DEV_IMAGE ?=$(WORKTREE_SLUG)-dev
|
|
11
|
+
DEV_TAG ?=dev
|
|
12
|
+
DEV_IMAGE_REF := $(DEV_IMAGE):$(DEV_TAG)
|
|
13
|
+
COMPOSE ?=COMPOSE_PROJECT_NAME=$(COMPOSE_PROJECT_NAME) docker compose
|
|
14
|
+
DEV_COMPOSE_FILE ?=compose.dev.yaml
|
|
15
|
+
DEV_SERVICE ?=app-dev
|
|
16
|
+
GOPROXY ?=https://proxy.golang.org,direct
|
|
17
|
+
GOSUMDB ?=sum.golang.org
|
|
18
|
+
BUILDER_IMAGE ?=golang:1.26-alpine
|
|
19
|
+
RUNTIME_IMAGE ?=alpine:3.20
|
|
20
|
+
WORKER_RUN_MODE ?={{RUN_MODE}}
|
|
21
|
+
WORKER_TICK_INTERVAL_SECONDS ?={{TICK_INTERVAL_SECONDS}}
|
|
22
|
+
WORKER_SHUTDOWN_TIMEOUT_SECONDS ?={{SHUTDOWN_TIMEOUT_SECONDS}}
|
|
23
|
+
WORKER_RETRY_MAX_ATTEMPTS ?=3
|
|
24
|
+
WORKER_RETRY_INITIAL_BACKOFF_SECONDS ?=1
|
|
25
|
+
WORKER_RETRY_MAX_BACKOFF_SECONDS ?=30
|
|
26
|
+
GOCACHE ?= $(CURDIR)/.cache/go-build
|
|
27
|
+
GOMODCACHE ?= $(CURDIR)/.cache/go-mod
|
|
28
|
+
export COMPOSE_PROJECT_NAME
|
|
29
|
+
export DEV_IMAGE
|
|
30
|
+
export DEV_TAG
|
|
31
|
+
export WORKER_RUN_MODE
|
|
32
|
+
export WORKER_TICK_INTERVAL_SECONDS
|
|
33
|
+
export WORKER_SHUTDOWN_TIMEOUT_SECONDS
|
|
34
|
+
export WORKER_RETRY_MAX_ATTEMPTS
|
|
35
|
+
export WORKER_RETRY_INITIAL_BACKOFF_SECONDS
|
|
36
|
+
export WORKER_RETRY_MAX_BACKOFF_SECONDS
|
|
37
|
+
export GOCACHE
|
|
38
|
+
export GOMODCACHE
|
|
39
|
+
|
|
40
|
+
.PHONY: worktree-info worktree-doctor worktree-compose-config clean-worktree bootstrap doctor dev dev-shell lint test verify run build clean help docker-build docker-run
|
|
41
|
+
|
|
42
|
+
worktree-info:
|
|
43
|
+
@printf '%s\n' "Worktree root: $(WORKTREE_ROOT)"
|
|
44
|
+
@printf '%s\n' "Worktree label: $(WORKTREE_LABEL)"
|
|
45
|
+
@printf '%s\n' "Worktree ID: $(WORKTREE_ID)"
|
|
46
|
+
@printf '%s\n' "Worktree slug: $(WORKTREE_SLUG)"
|
|
47
|
+
@printf '%s\n' "Compose project: $(COMPOSE_PROJECT_NAME)"
|
|
48
|
+
@printf '%s\n' "Dev image ref: $(DEV_IMAGE_REF)"
|
|
49
|
+
@printf '%s\n' "Runtime image ref: $(IMAGE_REF)"
|
|
50
|
+
@printf '%s\n' "Go cache: $(GOCACHE)"
|
|
51
|
+
@printf '%s\n' "Go module cache: $(GOMODCACHE)"
|
|
52
|
+
@printf '%s\n' "Worker run mode: $(WORKER_RUN_MODE)"
|
|
53
|
+
@printf '%s\n' "Worker retry attempts: $(WORKER_RETRY_MAX_ATTEMPTS)"
|
|
54
|
+
|
|
55
|
+
worktree-doctor:
|
|
56
|
+
@$(MAKE) --no-print-directory worktree-info
|
|
57
|
+
@case "$(GOCACHE)" in "$(WORKTREE_ROOT)"/*) ;; *) printf '%s\n' "GOCACHE should stay inside this worktree: $(GOCACHE)"; exit 1;; esac
|
|
58
|
+
@case "$(GOMODCACHE)" in "$(WORKTREE_ROOT)"/*) ;; *) printf '%s\n' "GOMODCACHE should stay inside this worktree: $(GOMODCACHE)"; exit 1;; esac
|
|
59
|
+
@printf '%s\n' "Worker has no published host ports by default."
|
|
60
|
+
@printf '%s\n' "Compose config check: make worktree-compose-config"
|
|
61
|
+
|
|
62
|
+
worktree-compose-config:
|
|
63
|
+
@if ! command -v docker >/dev/null 2>&1; then printf '%s\n' "Docker is not available; cannot render Compose config."; exit 1; fi
|
|
64
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) config
|
|
65
|
+
|
|
66
|
+
clean-worktree:
|
|
67
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) down --remove-orphans --volumes
|
|
68
|
+
|
|
69
|
+
bootstrap:
|
|
70
|
+
GOPROXY=$(GOPROXY) GOSUMDB=$(GOSUMDB) $(COMPOSE) -f $(DEV_COMPOSE_FILE) build $(DEV_SERVICE)
|
|
71
|
+
|
|
72
|
+
doctor:
|
|
73
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) ./scripts/doctor
|
|
74
|
+
|
|
75
|
+
lint:
|
|
76
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go vet ./...
|
|
77
|
+
|
|
78
|
+
dev:
|
|
79
|
+
WORKER_RUN_MODE=$(WORKER_RUN_MODE) WORKER_TICK_INTERVAL_SECONDS=$(WORKER_TICK_INTERVAL_SECONDS) WORKER_SHUTDOWN_TIMEOUT_SECONDS=$(WORKER_SHUTDOWN_TIMEOUT_SECONDS) WORKER_RETRY_MAX_ATTEMPTS=$(WORKER_RETRY_MAX_ATTEMPTS) WORKER_RETRY_INITIAL_BACKOFF_SECONDS=$(WORKER_RETRY_INITIAL_BACKOFF_SECONDS) WORKER_RETRY_MAX_BACKOFF_SECONDS=$(WORKER_RETRY_MAX_BACKOFF_SECONDS) GOPROXY=$(GOPROXY) GOSUMDB=$(GOSUMDB) $(COMPOSE) -f $(DEV_COMPOSE_FILE) up $(DEV_SERVICE)
|
|
80
|
+
|
|
81
|
+
dev-shell:
|
|
82
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) sh
|
|
83
|
+
|
|
84
|
+
test:
|
|
85
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go test ./...
|
|
86
|
+
|
|
87
|
+
verify: doctor lint test build
|
|
88
|
+
|
|
89
|
+
run:
|
|
90
|
+
WORKER_RUN_MODE=$(WORKER_RUN_MODE) WORKER_TICK_INTERVAL_SECONDS=$(WORKER_TICK_INTERVAL_SECONDS) WORKER_SHUTDOWN_TIMEOUT_SECONDS=$(WORKER_SHUTDOWN_TIMEOUT_SECONDS) WORKER_RETRY_MAX_ATTEMPTS=$(WORKER_RETRY_MAX_ATTEMPTS) WORKER_RETRY_INITIAL_BACKOFF_SECONDS=$(WORKER_RETRY_INITIAL_BACKOFF_SECONDS) WORKER_RETRY_MAX_BACKOFF_SECONDS=$(WORKER_RETRY_MAX_BACKOFF_SECONDS) $(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE)
|
|
91
|
+
|
|
92
|
+
build:
|
|
93
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) run --rm $(DEV_SERVICE) go build -o bin/$(APP_NAME) ./cmd/worker
|
|
94
|
+
|
|
95
|
+
clean:
|
|
96
|
+
$(COMPOSE) -f $(DEV_COMPOSE_FILE) down --remove-orphans
|
|
97
|
+
|
|
98
|
+
help:
|
|
99
|
+
@printf '%s\n' "Common commands:" " make bootstrap Prepare the development environment" " make doctor Check required tools and project configuration" " make lint Run static analysis" " make test Run tests" " make verify Run the complete local verification contract" " make build Build the application" " make clean Remove generated runtime state" " make help Show this command summary"
|
|
100
|
+
|
|
101
|
+
docker-build:
|
|
102
|
+
docker build --build-arg BUILDER_IMAGE=$(BUILDER_IMAGE) --build-arg RUNTIME_IMAGE=$(RUNTIME_IMAGE) --build-arg GOPROXY=$(GOPROXY) --build-arg GOSUMDB=$(GOSUMDB) -t $(IMAGE_REF) .
|
|
103
|
+
|
|
104
|
+
docker-run:
|
|
105
|
+
docker run --rm -e WORKER_RUN_MODE=$(WORKER_RUN_MODE) -e WORKER_TICK_INTERVAL_SECONDS=$(WORKER_TICK_INTERVAL_SECONDS) -e WORKER_SHUTDOWN_TIMEOUT_SECONDS=$(WORKER_SHUTDOWN_TIMEOUT_SECONDS) -e WORKER_RETRY_MAX_ATTEMPTS=$(WORKER_RETRY_MAX_ATTEMPTS) -e WORKER_RETRY_INITIAL_BACKOFF_SECONDS=$(WORKER_RETRY_INITIAL_BACKOFF_SECONDS) -e WORKER_RETRY_MAX_BACKOFF_SECONDS=$(WORKER_RETRY_MAX_BACKOFF_SECONDS) $(IMAGE_REF)
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# {{WORKER_NAME}}
|
|
2
|
+
|
|
3
|
+
This project was generated by BiucingCLI.
|
|
4
|
+
|
|
5
|
+
## Stack
|
|
6
|
+
|
|
7
|
+
- Go
|
|
8
|
+
- Docker
|
|
9
|
+
|
|
10
|
+
## Project Layout
|
|
11
|
+
|
|
12
|
+
- `cmd/worker`: background process entrypoint
|
|
13
|
+
- `internal/config`: config loading and environment overrides
|
|
14
|
+
- `internal/runtime`: execution loop and graceful shutdown behavior
|
|
15
|
+
- `internal/task`: starter task implementation
|
|
16
|
+
- `configs`: local config files
|
|
17
|
+
- `tests`: generated-project runtime tests
|
|
18
|
+
|
|
19
|
+
## Worker Shape
|
|
20
|
+
|
|
21
|
+
This starter is intentionally narrow:
|
|
22
|
+
|
|
23
|
+
- it is designed for background execution rather than a public HTTP API;
|
|
24
|
+
- it supports `scheduled` and `oneshot` execution modes;
|
|
25
|
+
- it keeps operational basics such as config loading, logging, and graceful shutdown explicit.
|
|
26
|
+
|
|
27
|
+
The default config file is `configs/config.json`.
|
|
28
|
+
|
|
29
|
+
## Docker Workflow
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
make bootstrap
|
|
33
|
+
make dev
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The starter is designed to run development, checks, and runtime packaging inside Docker by default.
|
|
37
|
+
|
|
38
|
+
## Available Commands
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
make bootstrap
|
|
42
|
+
make dev
|
|
43
|
+
make dev-shell
|
|
44
|
+
make doctor
|
|
45
|
+
make lint
|
|
46
|
+
make test
|
|
47
|
+
make verify
|
|
48
|
+
make build
|
|
49
|
+
make docker-build
|
|
50
|
+
make docker-run
|
|
51
|
+
make clean
|
|
52
|
+
make help
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Execution Modes
|
|
56
|
+
|
|
57
|
+
- `scheduled`: runs the starter task immediately and then on a repeating interval
|
|
58
|
+
- `oneshot`: runs the starter task once and exits
|
|
59
|
+
|
|
60
|
+
Each execution cycle has explicit retry semantics:
|
|
61
|
+
|
|
62
|
+
- `retry_max_attempts` includes the initial attempt; set it to `1` to disable retries.
|
|
63
|
+
- failed attempts use exponential backoff from `retry_initial_backoff_seconds`, capped by `retry_max_backoff_seconds`.
|
|
64
|
+
- `oneshot` returns the final error after retries are exhausted, so the process exits non-zero.
|
|
65
|
+
- `scheduled` logs an exhausted cycle, waits one `tick_interval_seconds` fixed delay, and starts the next cycle.
|
|
66
|
+
- cancellation interrupts scheduled waits and retry backoff immediately. An active task receives a canceled context and has `shutdown_timeout_seconds` to return before shutdown fails.
|
|
67
|
+
|
|
68
|
+
The generated defaults are:
|
|
69
|
+
|
|
70
|
+
- `run_mode={{RUN_MODE}}`
|
|
71
|
+
- `tick_interval_seconds={{TICK_INTERVAL_SECONDS}}`
|
|
72
|
+
- `shutdown_timeout_seconds={{SHUTDOWN_TIMEOUT_SECONDS}}`
|
|
73
|
+
- `retry_max_attempts=3`
|
|
74
|
+
- `retry_initial_backoff_seconds=1`
|
|
75
|
+
- `retry_max_backoff_seconds=30`
|
|
76
|
+
|
|
77
|
+
You can override them with environment variables:
|
|
78
|
+
|
|
79
|
+
- `WORKER_NAME`
|
|
80
|
+
- `WORKER_RUN_MODE`
|
|
81
|
+
- `WORKER_TICK_INTERVAL_SECONDS`
|
|
82
|
+
- `WORKER_SHUTDOWN_TIMEOUT_SECONDS`
|
|
83
|
+
- `WORKER_RETRY_MAX_ATTEMPTS`
|
|
84
|
+
- `WORKER_RETRY_INITIAL_BACKOFF_SECONDS`
|
|
85
|
+
- `WORKER_RETRY_MAX_BACKOFF_SECONDS`
|
|
86
|
+
- `CONFIG_FILE`
|
|
87
|
+
|
|
88
|
+
Example oneshot run:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
WORKER_RUN_MODE=oneshot make run
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Example scheduled run with a shorter loop:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
WORKER_RUN_MODE=scheduled WORKER_TICK_INTERVAL_SECONDS=5 make dev
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Environment
|
|
101
|
+
|
|
102
|
+
- `Brewfile`: optional host workstation tool installation
|
|
103
|
+
- `.mise.toml`: pinned Go version for host workflows
|
|
104
|
+
- `Dockerfile.dev`: development image used by Docker Compose
|
|
105
|
+
- `compose.dev.yaml`: local Docker development workflow
|
|
106
|
+
- `scripts/bootstrap`: host-oriented setup helper when you do not use Docker
|
|
107
|
+
- `scripts/doctor`: local environment checks
|
|
108
|
+
|
|
109
|
+
## Runtime Packaging
|
|
110
|
+
|
|
111
|
+
Build the runtime image:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
make docker-build
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Run the runtime image with the default scheduled mode:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
make docker-run
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Run the runtime image once and exit:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
make docker-run WORKER_RUN_MODE=oneshot
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The runtime image defaults are:
|
|
130
|
+
|
|
131
|
+
- `BUILDER_IMAGE=golang:1.26-alpine`
|
|
132
|
+
- `RUNTIME_IMAGE=alpine:3.20`
|
|
133
|
+
|
|
134
|
+
## Worktree Workflow
|
|
135
|
+
|
|
136
|
+
This starter is safe to run from parallel Git worktrees without publishing host ports by default.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
make worktree-info
|
|
140
|
+
make worktree-doctor
|
|
141
|
+
make worktree-compose-config
|
|
142
|
+
make dev
|
|
143
|
+
make clean-worktree
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- `WORKTREE_LABEL` is derived from the worktree directory name for display.
|
|
147
|
+
- `WORKTREE_ID` is derived from the current worktree path by default and can be overridden.
|
|
148
|
+
- `COMPOSE_PROJECT_NAME` defaults to `{{WORKER_NAME}}-$(WORKTREE_ID)`, so Compose containers, networks, and cache volumes stay scoped to the worktree.
|
|
149
|
+
- `DEV_IMAGE` and `IMAGE` default to worktree-specific names so dev/runtime image tags do not overwrite another worktree by default.
|
|
150
|
+
- `GOCACHE` and `GOMODCACHE` stay under the current worktree's `.cache/` directory.
|
|
151
|
+
- The Docker dev workflow mounts Go build and module caches as Compose-scoped volumes, so dependency versions and downloads do not bleed across worktrees.
|
|
152
|
+
- `make worktree-compose-config` renders the current worktree's Compose config without starting containers.
|
|
153
|
+
- `make clean-worktree` removes only the current worktree's Compose containers, networks, and volumes.
|
|
154
|
+
|
|
155
|
+
## Validation
|
|
156
|
+
|
|
157
|
+
The generated project includes:
|
|
158
|
+
|
|
159
|
+
- config-loading tests under `internal/config`
|
|
160
|
+
- runtime-loop tests under `internal/runtime`
|
|
161
|
+
- deterministic retry, fixed-delay scheduling, cancellation, and shutdown-timeout tests using an injected clock; they do not sleep to advance worker time
|
|
162
|
+
- a generated-project test under `tests/worker_test.go`
|
|
163
|
+
|
|
164
|
+
`make verify` runs the local doctor checks plus `go test ./...` inside Docker.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
package main
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"log"
|
|
6
|
+
"os"
|
|
7
|
+
"os/signal"
|
|
8
|
+
"syscall"
|
|
9
|
+
"time"
|
|
10
|
+
|
|
11
|
+
"{{MODULE_NAME}}/internal/config"
|
|
12
|
+
"{{MODULE_NAME}}/internal/runtime"
|
|
13
|
+
"{{MODULE_NAME}}/internal/task"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
func main() {
|
|
17
|
+
cfg, err := config.Load()
|
|
18
|
+
if err != nil {
|
|
19
|
+
log.Fatalf("load config: %v", err)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
23
|
+
defer stop()
|
|
24
|
+
|
|
25
|
+
logger := log.New(os.Stdout, "", log.LstdFlags)
|
|
26
|
+
runner := runtime.New(runtime.Options{
|
|
27
|
+
Name: cfg.Worker.Name,
|
|
28
|
+
Mode: cfg.Worker.RunMode,
|
|
29
|
+
TickInterval: time.Duration(cfg.Worker.TickIntervalSeconds) * time.Second,
|
|
30
|
+
ShutdownTimeout: time.Duration(cfg.Worker.ShutdownTimeoutSeconds) * time.Second,
|
|
31
|
+
MaxAttempts: cfg.Worker.RetryMaxAttempts,
|
|
32
|
+
InitialBackoff: time.Duration(cfg.Worker.RetryInitialSeconds) * time.Second,
|
|
33
|
+
MaxBackoff: time.Duration(cfg.Worker.RetryMaxSeconds) * time.Second,
|
|
34
|
+
Executor: task.NewHeartbeatTask(cfg.Worker.Name),
|
|
35
|
+
Logger: logger,
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
if err := runner.Run(ctx); err != nil {
|
|
39
|
+
log.Fatalf("run worker: %v", err)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
services:
|
|
2
|
+
app-dev:
|
|
3
|
+
build:
|
|
4
|
+
context: .
|
|
5
|
+
dockerfile: Dockerfile.dev
|
|
6
|
+
args:
|
|
7
|
+
GOPROXY: ${GOPROXY:-https://proxy.golang.org,direct}
|
|
8
|
+
GOSUMDB: ${GOSUMDB:-sum.golang.org}
|
|
9
|
+
image: ${DEV_IMAGE:-{{WORKER_NAME}}-dev}:${DEV_TAG:-latest}
|
|
10
|
+
working_dir: /app
|
|
11
|
+
environment:
|
|
12
|
+
CONFIG_FILE: configs/config.json
|
|
13
|
+
WORKER_RUN_MODE: ${WORKER_RUN_MODE:-{{RUN_MODE}}}
|
|
14
|
+
WORKER_TICK_INTERVAL_SECONDS: ${WORKER_TICK_INTERVAL_SECONDS:-{{TICK_INTERVAL_SECONDS}}}
|
|
15
|
+
WORKER_SHUTDOWN_TIMEOUT_SECONDS: ${WORKER_SHUTDOWN_TIMEOUT_SECONDS:-{{SHUTDOWN_TIMEOUT_SECONDS}}}
|
|
16
|
+
WORKER_RETRY_MAX_ATTEMPTS: ${WORKER_RETRY_MAX_ATTEMPTS:-3}
|
|
17
|
+
WORKER_RETRY_INITIAL_BACKOFF_SECONDS: ${WORKER_RETRY_INITIAL_BACKOFF_SECONDS:-1}
|
|
18
|
+
WORKER_RETRY_MAX_BACKOFF_SECONDS: ${WORKER_RETRY_MAX_BACKOFF_SECONDS:-30}
|
|
19
|
+
GOCACHE: /cache/go-build
|
|
20
|
+
GOMODCACHE: /cache/go-mod
|
|
21
|
+
volumes:
|
|
22
|
+
- .:/app
|
|
23
|
+
- worker-go-build-cache:/cache/go-build
|
|
24
|
+
- worker-go-mod-cache:/cache/go-mod
|
|
25
|
+
command: sh -lc "go run ./cmd/worker"
|
|
26
|
+
|
|
27
|
+
volumes:
|
|
28
|
+
worker-go-build-cache:
|
|
29
|
+
worker-go-mod-cache:
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"worker": {
|
|
3
|
+
"name": "{{WORKER_NAME}}",
|
|
4
|
+
"run_mode": "{{RUN_MODE}}",
|
|
5
|
+
"tick_interval_seconds": {{TICK_INTERVAL_SECONDS}},
|
|
6
|
+
"shutdown_timeout_seconds": {{SHUTDOWN_TIMEOUT_SECONDS}},
|
|
7
|
+
"retry_max_attempts": 3,
|
|
8
|
+
"retry_initial_backoff_seconds": 1,
|
|
9
|
+
"retry_max_backoff_seconds": 30
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
package config
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"errors"
|
|
6
|
+
"os"
|
|
7
|
+
"strconv"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
const defaultConfigFile = "configs/config.json"
|
|
11
|
+
|
|
12
|
+
type Config struct {
|
|
13
|
+
Worker WorkerConfig `json:"worker"`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type WorkerConfig struct {
|
|
17
|
+
Name string `json:"name"`
|
|
18
|
+
RunMode string `json:"run_mode"`
|
|
19
|
+
TickIntervalSeconds int `json:"tick_interval_seconds"`
|
|
20
|
+
ShutdownTimeoutSeconds int `json:"shutdown_timeout_seconds"`
|
|
21
|
+
RetryMaxAttempts int `json:"retry_max_attempts"`
|
|
22
|
+
RetryInitialSeconds int `json:"retry_initial_backoff_seconds"`
|
|
23
|
+
RetryMaxSeconds int `json:"retry_max_backoff_seconds"`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func Load() (Config, error) {
|
|
27
|
+
configFile := os.Getenv("CONFIG_FILE")
|
|
28
|
+
if configFile == "" {
|
|
29
|
+
configFile = defaultConfigFile
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
data, err := os.ReadFile(configFile)
|
|
33
|
+
if err != nil {
|
|
34
|
+
return Config{}, err
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var cfg Config
|
|
38
|
+
if err := json.Unmarshal(data, &cfg); err != nil {
|
|
39
|
+
return Config{}, err
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
applyStringOverride("WORKER_NAME", &cfg.Worker.Name)
|
|
43
|
+
applyStringOverride("WORKER_RUN_MODE", &cfg.Worker.RunMode)
|
|
44
|
+
if err := applyIntOverride("WORKER_TICK_INTERVAL_SECONDS", &cfg.Worker.TickIntervalSeconds); err != nil {
|
|
45
|
+
return Config{}, err
|
|
46
|
+
}
|
|
47
|
+
if err := applyIntOverride("WORKER_SHUTDOWN_TIMEOUT_SECONDS", &cfg.Worker.ShutdownTimeoutSeconds); err != nil {
|
|
48
|
+
return Config{}, err
|
|
49
|
+
}
|
|
50
|
+
if err := applyIntOverride("WORKER_RETRY_MAX_ATTEMPTS", &cfg.Worker.RetryMaxAttempts); err != nil {
|
|
51
|
+
return Config{}, err
|
|
52
|
+
}
|
|
53
|
+
if err := applyIntOverride("WORKER_RETRY_INITIAL_BACKOFF_SECONDS", &cfg.Worker.RetryInitialSeconds); err != nil {
|
|
54
|
+
return Config{}, err
|
|
55
|
+
}
|
|
56
|
+
if err := applyIntOverride("WORKER_RETRY_MAX_BACKOFF_SECONDS", &cfg.Worker.RetryMaxSeconds); err != nil {
|
|
57
|
+
return Config{}, err
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if cfg.Worker.Name == "" {
|
|
61
|
+
return Config{}, errors.New("worker.name is required")
|
|
62
|
+
}
|
|
63
|
+
if cfg.Worker.RunMode == "" {
|
|
64
|
+
cfg.Worker.RunMode = "{{RUN_MODE}}"
|
|
65
|
+
}
|
|
66
|
+
if cfg.Worker.RunMode != "scheduled" && cfg.Worker.RunMode != "oneshot" {
|
|
67
|
+
return Config{}, errors.New("worker.run_mode must be one of: scheduled, oneshot")
|
|
68
|
+
}
|
|
69
|
+
if cfg.Worker.TickIntervalSeconds <= 0 {
|
|
70
|
+
cfg.Worker.TickIntervalSeconds = {{TICK_INTERVAL_SECONDS}}
|
|
71
|
+
}
|
|
72
|
+
if cfg.Worker.ShutdownTimeoutSeconds <= 0 {
|
|
73
|
+
cfg.Worker.ShutdownTimeoutSeconds = {{SHUTDOWN_TIMEOUT_SECONDS}}
|
|
74
|
+
}
|
|
75
|
+
if cfg.Worker.RetryMaxAttempts <= 0 {
|
|
76
|
+
cfg.Worker.RetryMaxAttempts = 3
|
|
77
|
+
}
|
|
78
|
+
if cfg.Worker.RetryInitialSeconds <= 0 {
|
|
79
|
+
cfg.Worker.RetryInitialSeconds = 1
|
|
80
|
+
}
|
|
81
|
+
if cfg.Worker.RetryMaxSeconds <= 0 {
|
|
82
|
+
cfg.Worker.RetryMaxSeconds = 30
|
|
83
|
+
}
|
|
84
|
+
if cfg.Worker.RetryMaxSeconds < cfg.Worker.RetryInitialSeconds {
|
|
85
|
+
return Config{}, errors.New("worker.retry_max_backoff_seconds must be greater than or equal to worker.retry_initial_backoff_seconds")
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return cfg, nil
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
func applyStringOverride(envKey string, target *string) {
|
|
92
|
+
if value := os.Getenv(envKey); value != "" {
|
|
93
|
+
*target = value
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
func applyIntOverride(envKey string, target *int) error {
|
|
98
|
+
value := os.Getenv(envKey)
|
|
99
|
+
if value == "" {
|
|
100
|
+
return nil
|
|
101
|
+
}
|
|
102
|
+
parsed, err := strconv.Atoi(value)
|
|
103
|
+
if err != nil {
|
|
104
|
+
return errors.New(envKey + " must be an integer")
|
|
105
|
+
}
|
|
106
|
+
*target = parsed
|
|
107
|
+
return nil
|
|
108
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
package config
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"os"
|
|
5
|
+
"path/filepath"
|
|
6
|
+
"testing"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
func TestLoadDefaults(t *testing.T) {
|
|
10
|
+
tempDir := t.TempDir()
|
|
11
|
+
configPath := filepath.Join(tempDir, "config.json")
|
|
12
|
+
if err := os.WriteFile(configPath, []byte(`{"worker":{"name":"demo-worker","run_mode":"scheduled","tick_interval_seconds":15,"shutdown_timeout_seconds":8}}`), 0o644); err != nil {
|
|
13
|
+
t.Fatal(err)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
t.Setenv("CONFIG_FILE", configPath)
|
|
17
|
+
|
|
18
|
+
cfg, err := Load()
|
|
19
|
+
if err != nil {
|
|
20
|
+
t.Fatal(err)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if cfg.Worker.Name != "demo-worker" {
|
|
24
|
+
t.Fatalf("expected worker name %q, got %q", "demo-worker", cfg.Worker.Name)
|
|
25
|
+
}
|
|
26
|
+
if cfg.Worker.RunMode != "scheduled" {
|
|
27
|
+
t.Fatalf("expected run mode %q, got %q", "scheduled", cfg.Worker.RunMode)
|
|
28
|
+
}
|
|
29
|
+
if cfg.Worker.TickIntervalSeconds != 15 {
|
|
30
|
+
t.Fatalf("expected tick interval %d, got %d", 15, cfg.Worker.TickIntervalSeconds)
|
|
31
|
+
}
|
|
32
|
+
if cfg.Worker.RetryMaxAttempts != 3 || cfg.Worker.RetryInitialSeconds != 1 || cfg.Worker.RetryMaxSeconds != 30 {
|
|
33
|
+
t.Fatalf("unexpected retry defaults: %+v", cfg.Worker)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func TestLoadUsesEnvironmentOverrides(t *testing.T) {
|
|
38
|
+
tempDir := t.TempDir()
|
|
39
|
+
configPath := filepath.Join(tempDir, "config.json")
|
|
40
|
+
if err := os.WriteFile(configPath, []byte(`{"worker":{"name":"demo-worker","run_mode":"scheduled","tick_interval_seconds":15,"shutdown_timeout_seconds":8}}`), 0o644); err != nil {
|
|
41
|
+
t.Fatal(err)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
t.Setenv("CONFIG_FILE", configPath)
|
|
45
|
+
t.Setenv("WORKER_NAME", "override-worker")
|
|
46
|
+
t.Setenv("WORKER_RUN_MODE", "oneshot")
|
|
47
|
+
t.Setenv("WORKER_TICK_INTERVAL_SECONDS", "3")
|
|
48
|
+
t.Setenv("WORKER_SHUTDOWN_TIMEOUT_SECONDS", "2")
|
|
49
|
+
t.Setenv("WORKER_RETRY_MAX_ATTEMPTS", "5")
|
|
50
|
+
t.Setenv("WORKER_RETRY_INITIAL_BACKOFF_SECONDS", "2")
|
|
51
|
+
t.Setenv("WORKER_RETRY_MAX_BACKOFF_SECONDS", "8")
|
|
52
|
+
|
|
53
|
+
cfg, err := Load()
|
|
54
|
+
if err != nil {
|
|
55
|
+
t.Fatal(err)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if cfg.Worker.Name != "override-worker" {
|
|
59
|
+
t.Fatalf("expected worker name %q, got %q", "override-worker", cfg.Worker.Name)
|
|
60
|
+
}
|
|
61
|
+
if cfg.Worker.RunMode != "oneshot" {
|
|
62
|
+
t.Fatalf("expected run mode %q, got %q", "oneshot", cfg.Worker.RunMode)
|
|
63
|
+
}
|
|
64
|
+
if cfg.Worker.TickIntervalSeconds != 3 {
|
|
65
|
+
t.Fatalf("expected tick interval %d, got %d", 3, cfg.Worker.TickIntervalSeconds)
|
|
66
|
+
}
|
|
67
|
+
if cfg.Worker.ShutdownTimeoutSeconds != 2 {
|
|
68
|
+
t.Fatalf("expected shutdown timeout %d, got %d", 2, cfg.Worker.ShutdownTimeoutSeconds)
|
|
69
|
+
}
|
|
70
|
+
if cfg.Worker.RetryMaxAttempts != 5 || cfg.Worker.RetryInitialSeconds != 2 || cfg.Worker.RetryMaxSeconds != 8 {
|
|
71
|
+
t.Fatalf("unexpected retry overrides: %+v", cfg.Worker)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
func TestLoadRejectsRetryBackoffRange(t *testing.T) {
|
|
76
|
+
configPath := filepath.Join(t.TempDir(), "config.json")
|
|
77
|
+
data := []byte(`{"worker":{"name":"demo-worker","retry_initial_backoff_seconds":10,"retry_max_backoff_seconds":2}}`)
|
|
78
|
+
if err := os.WriteFile(configPath, data, 0o644); err != nil {
|
|
79
|
+
t.Fatal(err)
|
|
80
|
+
}
|
|
81
|
+
t.Setenv("CONFIG_FILE", configPath)
|
|
82
|
+
|
|
83
|
+
if _, err := Load(); err == nil {
|
|
84
|
+
t.Fatal("expected retry backoff range validation to fail")
|
|
85
|
+
}
|
|
86
|
+
}
|