Skip to content
Projects
Live2026

TaskForge

A Go task queue with gRPC, concurrent workers and an interactive terminal TUI.

Role
Backend Engineer
Status
Live
TaskForge
// Overview

TaskForge is a Cloud Tasks-inspired queue created as a portfolio project to explore backend fundamentals in Go. It allows tasks to be created, scheduled, listed, watched and cancelled through a gRPC API, a traditional CLI and an interactive terminal TUI. The project uses Protocol Buffers for the API contract, goroutines for concurrency, channels as the internal queue, a scheduler to dispatch delayed tasks and a worker pool to process jobs. It also includes retry handling with a simple backoff, a dead-letter state for tasks that exhaust their attempts and graceful server shutdown. It is deliberately scoped as a learning project: the store is in-memory, there is no authentication or database persistence yet, and the task handler is simulated with payloads like `fail` and `slow` to exercise the retry and dead-letter paths. The focus was concurrency and clean architecture, not production scale.

Key features

  • gRPC API with Protocol Buffers contracts.
  • CLI for creating, listing, watching and cancelling tasks.
  • Interactive terminal TUI with a dashboard and task navigation.
  • Scheduler for delayed tasks.
  • Concurrent worker pool using goroutines.
  • Internal queue based on channels.
  • Retry flow with a simple backoff.
  • Dead-letter state after max attempts.
  • Pretty terminal output and a server startup banner.
  • Graceful shutdown.
// Architecture

Architecture

Requests arrive through the CLI or the TUI, hit the gRPC server and land in the task store. The scheduler moves due tasks into a channel-based queue, which a concurrent worker pool consumes — each job ending as completed, retried or dead-lettered.

  • Flow: CLI/TUI → gRPC server → task store → scheduler → channel queue → worker pool → completed / retry / dead-letter.
  • Protocol Buffers define the API contract shared by the server and clients.
  • Goroutines and channels model the queue and the concurrent worker pool.
  • The scheduler dispatches delayed tasks once they become due.
  • Failed tasks retry with a simple backoff, then move to dead-letter after max attempts.
  • In-memory task store (no database persistence yet).
  • Graceful shutdown drains in-flight work before the server exits.
// Challenges & solutions

Challenges & solutions

Coordinating concurrent workers

Problem

Processing tasks in parallel without race conditions or leaking goroutines.

Solution

A channel-based queue feeds a fixed worker pool, and a graceful shutdown drains in-flight work and stops the goroutines cleanly.

Handling repeated failures

Problem

Deciding what should happen when a task keeps failing.

Solution

Failed tasks retry with a simple backoff and, once they exhaust their attempts, move to a dead-letter state instead of blocking the queue.

Watching the system live

Problem

Making the state of the queue easy to inspect straight from the terminal.

Solution

Beyond the CLI, an interactive TUI built with Bubble Tea and Lip Gloss shows a dashboard and lets you navigate tasks in real time.

// What I learned
  • How to model a queue with goroutines and channels in Go.
  • How to design a gRPC API with Protocol Buffers contracts.
  • How to implement retries, backoff and dead-letter handling.
  • How to build an interactive terminal TUI with Bubble Tea and Lip Gloss.
  • How to shut a concurrent server down gracefully.
// Tech stack
GogRPCProtocol BuffersGoroutinesChannelsBubble TeaLip GlossMakefile