+25
-6
@@ -6,10 +6,17 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RunnerFn is the function type for a runner. It receives a pointer to
|
||||
// the Bot and returns an error if execution fails.
|
||||
// RunnerFn is the legacy function type for a runner. It receives a pointer to
|
||||
// the Bot and returns an error if execution fails. New blocking or I/O work
|
||||
// should use ContextRunnerFn so runtime cancellation can stop the callback.
|
||||
//
|
||||
// Subject to change in v2: runner callbacks may require context.Context.
|
||||
type RunnerFn[T AppData] func(*Bot[T]) error
|
||||
|
||||
// ContextRunnerFn is a cancelable runner function.
|
||||
// The runtime context is canceled when polling or webhook execution stops.
|
||||
type ContextRunnerFn[T AppData] func(context.Context, *Bot[T]) error
|
||||
|
||||
// Runner represents a configurable background or one-time task to be
|
||||
// executed by a Bot.
|
||||
//
|
||||
@@ -26,14 +33,18 @@ type Runner[T AppData] struct {
|
||||
async bool // If true, runs in a goroutine; else, runs synchronously
|
||||
every time.Duration // Interval between periodic executions; zero means one-shot
|
||||
fn RunnerFn[T] // The function to execute
|
||||
ctxFn ContextRunnerFn[T]
|
||||
}
|
||||
|
||||
func executeRunner[T AppData](runner Runner[T], bot *Bot[T]) (err error) {
|
||||
func executeRunnerWithContext[T AppData](ctx context.Context, runner Runner[T], bot *Bot[T]) (err error) {
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
err = fmt.Errorf("runner %q panicked: %v", runner.name, recovered)
|
||||
}
|
||||
}()
|
||||
if runner.ctxFn != nil {
|
||||
return runner.ctxFn(ctx, bot)
|
||||
}
|
||||
if runner.fn == nil {
|
||||
return fmt.Errorf("runner %q has no function", runner.name)
|
||||
}
|
||||
@@ -46,10 +57,18 @@ func executeRunner[T AppData](runner Runner[T], bot *Bot[T]) (err error) {
|
||||
// goroutine that fires once when the bot runtime starts. Use Async and Every
|
||||
// to customize this. Do not call builder methods concurrently or after the
|
||||
// bot runtime has begun executing runners.
|
||||
//
|
||||
// Subject to change in v2: NewContextRunner may become the primary constructor.
|
||||
func NewRunner[T AppData](name string, fn RunnerFn[T]) Runner[T] {
|
||||
return Runner[T]{name: name, fn: fn, async: true, every: 0}
|
||||
}
|
||||
|
||||
// NewContextRunner creates a runner whose callback observes runtime cancellation.
|
||||
// It is the preferred constructor for I/O, blocking, and periodic work.
|
||||
func NewContextRunner[T AppData](name string, fn ContextRunnerFn[T]) Runner[T] {
|
||||
return Runner[T]{name: name, ctxFn: fn, async: true, every: 0}
|
||||
}
|
||||
|
||||
// Async sets whether the runner executes synchronously or asynchronously.
|
||||
// If true, the runner runs in a goroutine (non-blocking).
|
||||
// If false, the runner blocks the caller during execution.
|
||||
@@ -97,7 +116,7 @@ func (bot *Bot[T]) ExecRunners(ctx context.Context) {
|
||||
go func(r Runner[T]) {
|
||||
defer bot.runnerOnceWG.Done()
|
||||
startedAt := time.Now()
|
||||
err := executeRunner(r, bot)
|
||||
err := executeRunnerWithContext(ctx, r, bot)
|
||||
bot.safeEmitEvent(ctx, RunnerFinishedEvent{
|
||||
Name: r.name,
|
||||
Duration: time.Since(startedAt),
|
||||
@@ -117,7 +136,7 @@ func (bot *Bot[T]) ExecRunners(ctx context.Context) {
|
||||
} else if runner.every == 0 && !runner.async {
|
||||
// One-time sync: block until done
|
||||
t := time.Now()
|
||||
err := executeRunner(runner, bot)
|
||||
err := executeRunnerWithContext(ctx, runner, bot)
|
||||
elapsed := time.Since(t)
|
||||
bot.safeEmitEvent(ctx, RunnerFinishedEvent{
|
||||
Name: runner.name,
|
||||
@@ -158,7 +177,7 @@ func (bot *Bot[T]) ExecRunners(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
startedAt := time.Now()
|
||||
err := executeRunner(r, bot)
|
||||
err := executeRunnerWithContext(ctx, r, bot)
|
||||
bot.safeEmitEvent(ctx, RunnerFinishedEvent{
|
||||
Name: r.name,
|
||||
Duration: time.Since(startedAt),
|
||||
|
||||
Reference in New Issue
Block a user