This project is a serverless microservices architecture deployed to Google Cloud Platform (GCP). It leverages Node.js for the API Gateway and Worker services, and Go for the Scheduler service. Infrastructure provisioning is managed via Terraform (IaC), and automated CI/CD deployment is handled by GitHub Actions. The system is designed to run entirely for free under the GCP Free Tier limit.
┌──────────────────────────────────────────────────────────────┐
│ Developer │
│ git push main │
│ └──────┬────────────────────────────────┘
│ │
│ ▼
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ GitHub Actions │ │
│ │ ┌─────────────┐ ┌──────────────┐ ┌────────────────┐ │ │
│ │ │ Terraform │──>│ Docker Build │──>│ Deploy Cloud │ │ │
│ │ │ Apply │ │ & Push Image │ │ Run │ │ │
│ │ └─────────────┘ └──────────────┘ └────────────────┘ │ │
│ └───────────────────────────┬──────────────────────────────┘ │
└─────────────────────────────┼────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ GCP Project │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Artifact Registry │ │
│ │ (Stores Docker Images) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ API Gateway │ │ Scheduler │ │
│ │ Cloud Run │ │ Cloud Run │ │
│ │ (Node.js) │ │ (Go) │ │
│ │ │ │ │ │
│ │ CRUD items │ │ Manages schedule │ │
│ └──────┬───────┘ └────────┬─────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────────┐ │
│ │ │ Cloud Tasks │ │
│ │ │ Queue │ │
│ │ └────────┬─────────┘ │
│ │ │ │
│ │ ▼ │
│ │ ┌──────────────────┐ │
│ │ │ Worker │ │
│ │ │ Cloud Run │ │
│ │ │ (Node.js) │ │
│ │ │ │ │
│ │ │ Processes job │ │
│ │ └────────┬─────────┘ │
│ │ │ │
│ └─────────────────┬────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Firestore │ │
│ │ │ │
│ │ /items │ │
│ │ /job_results │ │
│ │ /scheduled_jobs│ │
│ └─────────────────┘ │
└──────────────────────────────────────────────────────────────┘
All Cloud Run services are configured with min_instances = 0 (scale to zero), meaning they scale down to zero instances when idle to prevent incurring any billing costs.
- API Gateway (Node.js): The main entry point. Receives external HTTP requests and performs CRUD operations on the
itemscollection in Firestore (Local Port: 3000). - Worker (Node.js): Asynchronously processes heavy background jobs and saves the results in the Firestore
job_resultscollection (Local Port: 3001). This service is private and only accessible by authorized service accounts (like Google Cloud Tasks). - Scheduler (Go): Stores scheduled tasks in the Firestore
scheduled_jobscollection. When triggered periodically via the/runendpoint, it queries due tasks and dispatches them to the Google Cloud Tasks Queue using OIDC tokens for secure and reliable job execution (Local Port: 3002).
cloud-task-engine/
│
├── README.md
├── start.bat Windows batch script to run all services locally
├── start_services.ps1 PowerShell helper script for local execution
├── key.json GCP Service Account credentials file (gitignored)
│
├── terraform/ Infrastructure as Code (IaC) configuration
│ ├── main.tf Main module connector
│ ├── variables.tf Input variable definitions
│ ├── outputs.tf Cloud Run output URLs
│ └── modules/ Sub-modules (Cloud Run, Firestore, IAM, Registry)
│
├── services/ Application Source Code
│ ├── api-gateway/ API Gateway Service (Node.js) + `.env.example`
│ ├── worker/ Background Worker Service (Node.js) + `.env.example`
│ └── scheduler/ Scheduler Service (Go) + `.env.example`
│
└── .github/
└── workflows/
└── deploy.yml CI/CD automated deployment workflow to GCP
Follow these step-by-step instructions to deploy the entire microservices stack to your Google Cloud Platform account.
- Log in to your GCP account via terminal using the gcloud CLI.
- Create a new GCP project using
gcloud projects create YOUR-PROJECT-ID. - Set your active project using
gcloud config set project YOUR-PROJECT-ID. - Enable billing for the project in the GCP Console to allow resource provisioning.
- Navigate to the
terraformdirectory in your workspace. - Copy the variables template using
cp terraform.tfvars.example terraform.tfvars. - Edit the
terraform.tfvarsfile and specify your configuration (enterproject_id,region, andenvironment). - Initialize Terraform:
terraform init. - Provision resources:
terraform apply(this creates Firestore, Artifact Registry, IAM roles, and sets up Cloud Run placeholder services).
Deployments are automated on git pushes via GitHub Actions using Workload Identity Federation (WIF) for keyless GCP authentication.
- Create and configure a Workload Identity Pool in your GCP project using gcloud CLI.
- Copy the resulting WIF provider resource path.
- Open your GitHub repository, go to Settings -> Secrets and variables -> Actions.
- Add the following repository secrets:
GCP_PROJECT_ID: Your GCP Project ID.WIF_PROVIDER: Your WIF provider resource path.WIF_SERVICE_ACCOUNT: The email address of the GitHub Actions service account created by Terraform (e.g.github-actions-sa@your-project-id.iam.gserviceaccount.com).
Commit and push your changes to your main branch to trigger the automated CI/CD deployment:
git add .
git commit -m "feat: complete configuration and deploy infrastructure"
git push origin mainTrack the build and deployment progress under the Actions tab of your GitHub repository.
After the GitHub Actions workflow successfully deploys the microservices, retrieve the public HTTPS URLs of the Cloud Run services.
- Navigate to the
terraformdirectory in your terminal:cd terraform - Run the following command to print the service URLs:
This will output the HTTPS endpoints:
terraform output
api_gateway_url: The URL for the Node.js API Gateway.scheduler_url: The URL for the Go Scheduler.worker_url: The URL for the private Node.js Worker.
Testing on GCP differs from local testing. Because Cloud Run manages the routing, there are no port numbers (services communicate securely over standard port 443 HTTPS).
-
Verify Health Status (Public Services):
- Open a browser or use Postman to send a
GETrequest to[api_gateway_url]/health(should return{ "status": "ok", "service": "api-gateway" }). - Send a
GETrequest to[scheduler_url]/health(should return{ "service": "scheduler", "status": "ok" }).
- Open a browser or use Postman to send a
-
Verify Worker Private Status:
- Send a
GETrequest to[worker_url]/healthor[worker_url]/results. - This should return a
403 Forbiddenerror. This is the expected security behavior: the Worker Cloud Run service is private (no-allow-unauthenticated) and is only accessible by Google Cloud Tasks queues or authorized service accounts using OIDC tokens.
- Send a
-
Schedule and Trigger Tasks:
- Send a
POSTrequest to[scheduler_url]/schedulewith JSON body:This should return{ "name": "gcp-sync-test", "run_at": "2026-01-01T00:00:00Z", "payload": { "cloud_mode": true } }201 Createdindicating the task document is stored in Firestore with statuspending. - Send a
POSTrequest to[scheduler_url]/runto trigger task execution. The Scheduler service will read the pending task and dispatch it to the Google Cloud Tasks Queue, which securely invokes the private Worker via OIDC. - Verify the task execution details by inspecting the collections (
scheduled_jobsandjob_results) inside the GCP Firestore console.
- Send a
To use the frontend dashboard with your live GCP Cloud Run environment:
- Open dashboard/dashboard.js and update the
apiBasevariable under the state configuration to point to your publicscheduler_url:const state = { theme: 'theme-glass-bento', viewState: 'nominal', dataSource: 'live', apiBase: 'https://scheduler-xxxxxx.a.run.app', // Replace with your scheduler_url ... };
- Start the local dashboard server:
node dashboard/serve.js
- Open
http://localhost:3050in your web browser. The dashboard will now communicate with the GCP Firestore database through the deployed Go Scheduler Cloud Run instance.
There are several ways to spin up the Firestore database and run the microservices locally. Choose the setup option that best fits your local environment.
- Node.js v18 or newer
- Go v1.21 or newer
This option is recommended if you want to test database writes/reads against your real GCP Firestore instance from your local computer.
- Go to GCP Console -> IAM & Admin -> Service Accounts.
- Select your service account (e.g.
cloud-run-saor create a new one with theCloud Datastore Userrole). - Click the Keys tab -> Add Key -> Create new key -> select JSON.
- Save the downloaded credential file as
key.jsoninside the root folder of this project. - Install service dependencies:
cd services/api-gateway && npm install && cd ../.. cd services/worker && npm install && cd ../.. cd services/scheduler && go mod tidy && cd ../..
- Spin up all services automatically by double-clicking the
start.batfile in the root folder, or running this in PowerShell:.\start.bat
A completely offline and free option utilizing the built-in emulator from the Google Cloud CLI.
- Ensure the gcloud CLI is installed on your computer.
- Install the emulator component:
gcloud components install cloud-firestore-emulator
- Start the local emulator:
gcloud emulators firestore start --host-port=localhost:8090
- In separate terminal windows, launch each service with the emulator host environment variable:
- API Gateway:
cd services/api-gateway $env:FIRESTORE_EMULATOR_HOST="localhost:8090" npm.cmd start
- Worker:
cd services/worker $env:FIRESTORE_EMULATOR_HOST="localhost:8090" npm.cmd start
- Scheduler:
(Note: In local testing, Go Scheduler automatically falls back to direct HTTP calls to the Worker since Google Cloud Tasks is a cloud-only resource. This keeps local development 100% offline and free).
cd services/scheduler $env:FIRESTORE_EMULATOR_HOST="localhost:8090" $env:GCP_PROJECT="local-dev" $env:WORKER_URL="http://localhost:3001" # QUEUE_PATH and CLOUD_RUN_SA_EMAIL are left blank in local testing go run main.go
- API Gateway:
An offline option if you do not want to install any local SDK binaries other than Docker.
- Ensure Docker Desktop is running on your machine.
- Spin up the official Google SDK container running the emulator:
docker run -d --name firestore-emulator -p 8090:8090 google/cloud-sdk:alpine gcloud beta emulators firestore start --host-port=0.0.0.0:8090
- Connect your local services to the Docker container by setting the environment variable
$env:FIRESTORE_EMULATOR_HOST="localhost:8090"before starting each process (refer to Option B for start commands).
An offline option if you want to avoid installing the Google Cloud CLI or Docker.
- Ensure Java v11 or newer is installed on your computer.
- Run the Firebase emulator suite directly using npx:
npx firebase-tools emulators:start --only firestore
- Connect your local services by setting
$env:FIRESTORE_EMULATOR_HOST="localhost:8090"before running them (refer to Option B for start commands).
This project features a live, interactive scheduler dashboard built using pure HTML, custom Vanilla CSS, and state-driven Javascript. The dashboard provides a visual interface for managing and triggering background tasks.
The upper section of the dashboard consists of:
- Connection Status Badge: A live status indicator in the top header that shows "Live API Loop" when the dashboard is successfully polling the local Go Scheduler.
- KPI Metrics Panel: Four real-time statistics cards:
- Total Dispatched: The cumulative count of all scheduled tasks.
- Currently Queued: The current number of jobs in a pending or running state.
- Success Rate: The percentage of completed tasks relative to failed ones.
- Avg Worker Latency: The average execution latency of the background workers.
- 3D Core Visualizer: An interactive 3D core representation that accelerates based on active scheduling workloads.
The lower section handles execution control and audit logging:
- Pending Jobs Queue: Lists jobs currently in a pending or running state. Users can click "Trigger /run" to manually dispatch due tasks or click the cancel button to delete a scheduled job.
- Task History Log: An interactive audit table for completed and failed job executions. It features text searching, filtering (by status and target type), sorting, pagination, and a client-side "Export CSV" tool.
- Quick Schedule Drawer: A slide-over panel to schedule new tasks. It includes fields for task name, dispatch target type, execution priority, delay interval, and a JSON payload editor.
The frontend dashboard interfaces directly with port 3002 (Go Scheduler).
- Port 3002 (Go Scheduler) acts as the coordinator for all task schedules. It handles the list and schedule requests (
GET /jobsandPOST /schedule), writing them to thescheduled_jobscollection in Firestore. - Port 3001 (Worker) is a private processor service that executes due tasks and writes results to the
job_resultscollection. It does not track pending schedules, so connecting the dashboard to port 3001 would make it impossible to list or manage the active queue. - Port 3000 (API Gateway) is designed for a separate CRUD collection (
/items) and is not involved in the task scheduler workflow. It is not integrated with the dashboard because the dashboard is focused exclusively on background jobs and queues.
To use the dashboard in live mode, you must run the backend API services (specifically Go Scheduler and Worker). If the Go Scheduler service on port 3002 is not running, the dashboard will display a connection error state and will fail to load or schedule tasks.
- Start the backend services (Go Scheduler and Worker). Ensure you have configured the
key.jsonfile in the root directory..\start.bat - Navigate to the dashboard directory and start the local static server:
node dashboard/serve.js
- Open
http://localhost:3050in your web browser. The dashboard will automatically connect to port 3002.
- Open the dashboard page. Verify that the connection badge in the header displays "Live API Loop".
- Click New Task to open the schedule drawer. Enter a task name, select a priority and dispatch target, and click Schedule Task.
- Confirm that the task appears in the Pending Jobs Queue card.
- Verify in the GCP Firestore console under the
scheduled_jobscollection that the new task document is written. - Click Trigger /run in the dashboard. Verify that the task executes, disappears from the pending queue, and is added to the Task History log as
completed.
Execute the following 8 testing steps in order inside Postman to verify the end-to-end functionality of your microservices:
Verifies the API Gateway (Port 3000) is running locally.
- Method:
GET - Request URL:
http://localhost:3000/health - Response:
200 OKwith JSON body{"status": "ok", "service": "api-gateway"}. - Screenshot Reference:

Verifies the Worker (Port 3001) is running locally.
- Method:
GET - Request URL:
http://localhost:3001/health - Response:
200 OKwith JSON body{"status": "ok", "service": "worker"}. - Screenshot Reference:

Verifies the Go Scheduler (Port 3002) is running locally.
- Method:
GET - Request URL:
http://localhost:3002/health - Response:
200 OKwith JSON body{"service": "scheduler", "status": "ok"}. - Screenshot Reference:

Creates a new document directly in your cloud Firestore instance.
- Method:
POST - Request URL:
http://localhost:3000/api/items - Headers:
Content-Type: application/json - Body (raw -> JSON):
{ "name": "Laptop ASUS ROG", "description": "Spesifikasi gaming Core i9" } - Response:
201 Createdwith JSON body containing the generated unique Firestore document ID. - Screenshot Reference:

Retrieves all items stored in the Firestore collection.
- Method:
GET - Request URL:
http://localhost:3000/api/items - Response:
200 OKwith a JSON array listing the items. - Screenshot Reference:

Registers a scheduled background job in the system.
- Method:
POST - Request URL:
http://localhost:3002/schedule - Headers:
Content-Type: application/json - Body (raw -> JSON):
{ "name": "send-welcome-email", "run_at": "2024-01-01T00:00:00Z", "payload": { "email": "user@example.com", "subject": "Selamat Datang!" } } - Response:
201 Createdshowing the created job status aspending. - Screenshot Reference:

Triggers the scheduler to parse due tasks and dispatch them to the Worker.
- Method:
POST - Request URL:
http://localhost:3002/run - Response:
200 OKshowing the number of executed jobs and their IDs. - Screenshot Reference:

Confirms that the Worker received the dispatched job and completed the background execution.



