allium
무료Give your AI agents something more useful than a prompt. Velocity through clarity.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Create scheduled background jobs that run on cron schedules
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Periodic tasks are scheduled background jobs that run on cron schedules. They use defperiodic to emit trigger events, and a corresponding defprocessor handles the actual work.
See Pattern Compendium section 1.4.1 for the authoritative reference.
Periodic tasks are split into two parts:
periodic_tasks.clj -- defperiodic emits a lightweight trigger event per tenant on scheduletodo_processors.clj -- defprocessor subscribes to the trigger event and does the real workThe framework iterates over all tenants automatically. The defperiodic handler receives [tenant-id time] (NOT [context time]) and returns {:result/events [...]}. The framework appends the events per-tenant.
core/periodic_tasks.clj)(ns ai.obney.orc.my-service.core.periodic-tasks
"Scheduled trigger events for my-service."
(:require [ai.obney.grain.event-store-v3.interface :refer [->event]]
[ai.obney.grain.periodic-task.interface :refer [defperiodic]]))
(defperiodic :my-service send-reminders
{:schedule {:cron "0 * * * *" :timezone "America/Chicago"}}
"Emit reminder-check trigger for each tenant every hour."
[_tenant-id time]
{:result/events
[(->event {:type :my-service/reminder-check-triggered
:tags #{[:reminder-check (random-uuid)]}
:body {:triggered-at (str time)}})]})
The generated var name is my-service-send-reminders.
core/todo_processors.clj)(ns ai.obney.orc.my-service.core.todo-processors
(:require [ai.obney.orc.my-service.core.read-models :as rm]
[ai.obney.grain.command-processor-v2.interface :as cp]
[ai.obney.grain.time.interface :as time]
[ai.obney.grain.todo-processor-v2.interface :refer [defprocessor]]
[com.brunobonacci.mulog :as u]))
(defprocessor :my-service reminder-runner
{:topics #{:my-service/reminder-check-triggered}}
"Process pending reminders when trigger fires."
[context]
(let [items (rm/get-pending-items context)]
(u/log ::reminder-runner :count (count items))
(doseq [item items]
(cp/process-command
(assoc context :command {:command/id (random-uuid)
:command/timestamp (time/now)
:command/name :my-service/send-reminder
:item-id (:id item)})))
{}))
;; periodic_tasks.clj
(defperiodic :membership billing-check
{:schedule {:cron "0 6 * * *" :timezone "America/Chicago"}}
"Daily billing check trigger."
[_tenant-id time]
{:result/events [(->event {:type :membership/billing-check-triggered
:tags #{[:billing-check (random-uuid)]}
:body {:triggered-at (str time)}})]})
;; todo_processors.clj
(defprocessor :membership billing-runner
{:topics #{:membership/billing-check-triggered}}
"Process memberships due for billing."
[context]
(let [today (str (java.time.LocalDate/now))
due (rm/get-memberships-due-for-billing context today)]
(doseq [m due]
(cp/process-command
(assoc context :command {:command/id (random-uuid)
:command/timestamp (time/now)
:command/name :membership/initiate-billing
:membership-id (:membership-id m)})))
{}))
| Format | Example | Description |
|---|---|---|
| Cron | {:cron "0 * * * *" :timezone "America/Chicago"} | Standard cron (minute hour day month weekday) |
Common cron patterns:
"0 * * * *" -- every hour on the hour"*/15 * * * *" -- every 15 minutes"0 3 * * *" -- daily at 3 AM"0 6 * * *" -- daily at 6 AM"0 0 * * 1" -- weekly on Monday at midnightWhen a trigger event must be processed at most once, use CAS inside the defprocessor:
(defprocessor :my-service digest-sender
{:topics #{:my-service/digest-triggered}}
"Send daily digest -- at most once per user per day."
[context]
(let [users (rm/get-users-needing-digest context)]
(doseq [user users]
(es/append (:event-store context)
{:tenant-id (:tenant-id context)
:events [(->event {:type :my-service/digest-sent
:tags #{[:user (:user-id user)]}
:body {:user-id (:user-id user)
:date (str (java.time.LocalDate/now))}})]
:cas {:types #{:my-service/digest-sent}
:tags #{[:user (:user-id user)]}
:predicate-fn (fn [existing]
(empty? (into [] existing)))}}))
{}))
The CAS predicate checks that no :my-service/digest-sent event exists for this user with these tags. If another instance already emitted one, the append silently fails.
Both defperiodic and defprocessor register in global registries automatically. No manual registry maps are needed.
Interface.clj only needs bare side-effect requires:
(ns ai.obney.orc.my-service.interface
(:require [ai.obney.orc.my-service.core.commands]
[ai.obney.orc.my-service.core.queries]
[ai.obney.orc.my-service.core.todo-processors] ;; bare require
[ai.obney.orc.my-service.core.periodic-tasks] ;; bare require
[ai.obney.orc.my-service.core.read-models :as rm]))
;; No periodic-tasks or todo-processors re-export needed
(def get-item rm/get-item)
No manual wiring is needed. pt/start-periodic-triggers! discovers periodic tasks from the global registry. The control plane discovers todo processors the same way.
components/membership-service/src/.../core/periodic_tasks.clj -- Billing check triggercomponents/scheduling-service/src/.../core/periodic_tasks.clj -- Scheduling triggerscomponents/user-service/src/.../core/periodic_tasks.clj -- User maintenancedocs/contributors/CONTRIBUTOR-GRAIN-PATTERNS.md section 1.4.1 -- Authoritative periodic task reference아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Give your AI agents something more useful than a prompt. Velocity through clarity.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Extract an Allium specification from an existing codebase. Use when the user has existing code and wants to distil behaviour into a spec, reverse engineer a specification from implementation, generate a spec from code, turn implementation into a behavioural specification, or document what a codebase does in Allium terms.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Run a structured discovery session to build an Allium specification through conversation. Use when the user wants to create a new spec from scratch, elicit or gather requirements, capture domain behaviour, specify a feature or system, define what a system should do, or is describing functionality and needs help shaping it into a specification.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Implement command handlers that validate state and emit events using the Grain framework
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Implement query handlers that read from event-sourced read models
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Build read models by reducing events into queryable state
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.