ListPendingObligations, the drain's work list, selects pending obligations only, so a failed obligation is a dead letter until RequeueFailedObligations, which the operator's Retry calls, sets it back to pending. The entitlement-set-history requirement says the drain selects failed rows as well; the change proposed for #187 corrects that sentence. The test marks one obligation failed, checks that the list leaves it out, requeues the set and checks that the list holds it again.
Temporal Workflows
This directory contains the Temporal workflow definitions, activity implementations, and worker configuration for the member-console application.
Structure: Domain-Based
We use a Domain-Based (or Feature-Based) structure. Instead of grouping all workflows in one folder and all activities in another, we group them by business domain.
internal/workflows/
├── client.go # Temporal client factory
├── worker.go # Central worker setup & registration
├── queues/
│ └── queues.go # Task Queue constants
├── common/ # Shared utilities & generic activities
│ └── options.go # Standard ActivityOptions (retries, timeouts)
├── example/ # "Example" Domain
│ ├── workflow.go # Workflow definition
│ └── activities.go # Domain-specific activities
├── fedwiki/ # "FedWiki" Domain - Site provisioning
│ ├── README.md # Domain documentation
│ ├── FARMMANAGER.md # FarmManager API documentation
│ ├── workflow.go # Create/Delete site workflows
│ ├── activities.go # Site management activities
│ └── farmmanager_client.go # HTTP client for FarmManager API
└── onboarding/ # (Future) "Onboarding" Domain
├── workflow.go
└── activities.go
Adding a New Domain
- Create a directory:
internal/workflows/<domain_name>/ - Define the Workflow: Create
workflow.goin that directory. - Define Activities: Create
activities.goin that directory.- Define a struct (e.g.,
Activities) to hold dependencies (DB, Logger). - Implement a
NewActivitiesconstructor.
- Define a struct (e.g.,
- Register: Go to
internal/workflows/worker.goand add your new domain to theNewWorkerfunction:
// internal/workflows/worker.go
// ... inside NewWorker ...
w.RegisterWorkflow(yourdomain.Workflow)
w.RegisterActivity(yourdomain.NewActivities(cfg.DB, cfg.Logger))
Usage
Starting the Worker
The worker is embedded in the main application but can be extracted later.
import "git.coopcloud.tech/wiki-cafe/member-console/internal/workflows"
// ... in your main setup ...
workerCfg := workflows.DefaultWorkerConfig(database, logger)
worker, err := workflows.NewWorker(temporalClient, workerCfg)
if err := worker.Start(); err != nil {
// handle error
}
defer worker.Stop()
Starting a Workflow
import (
"git.coopcloud.tech/wiki-cafe/member-console/internal/workflows"
"git.coopcloud.tech/wiki-cafe/member-console/internal/workflows/queues"
"git.coopcloud.tech/wiki-cafe/member-console/internal/workflows/example"
)
// ... inside an HTTP handler ...
workflowOpts := client.StartWorkflowOptions{
ID: "example-" + uuid.New().String(),
TaskQueue: queues.Main,
}
we, err := temporalClient.ExecuteWorkflow(
ctx,
workflowOpts,
example.Workflow, // Pass the function reference
example.Input{Message: "hello"},
)