Documentation
¶
Overview ¶
Package service 提供跨平台的服务(守护进程)管理框架。 支持 Windows、Linux(systemd/Upstart/SysV/OpenRC)、macOS launchd,自动检测交互/服务模式。
基本用法(Runner 接口,推荐):
// 注意:New() 现在仅接受 Interface 类型,Runner 请使用 NewFromRunner。
type myService struct{}
func (m *myService) Run(ctx context.Context) error {
<-ctx.Done()
return nil
}
func main() {
cfg := &service.Config{Name: "myapp"}
svc, _ := service.NewFromRunner(&myService{}, cfg)
_ = svc.Run()
}
使用 NewFromRunner(Runner 接口,推荐):
type myService struct{}
func (m *myService) Run(ctx context.Context) error {
<-ctx.Done()
return nil
}
func main() {
cfg := &service.Config{Name: "myapp"}
svc, _ := service.NewFromRunner(&myService{}, cfg)
_ = svc.Run()
}
函数式用法(ServiceRunner):
runner := service.NewServiceRunner(func(ctx context.Context) error {
<-ctx.Done()
return nil
})
svc, _ := service.New(runner, cfg)
_ = svc.Run()
传统用法(Interface,向后兼容):
type program struct{}
func (p *program) Start(s service.Service) error { go p.run(); return nil }
func (p *program) run() { /* 业务逻辑 */ }
func (p *program) Stop(s service.Service) error { return nil }
简化用法说明:
Runner 接口消除了手动管理 goroutine、channel 和 context 的样板代码。 与传统 Interface 相比,减少约 80% 的代码量,同时保持相同功能。 NewFromRunner 会自动将 Runner 包装为 ServiceRunner 并调用 New 创建 Service。
三种使用方式对比:
1. Runner 接口(推荐):实现 Run(ctx context.Context) error 方法
- 使用 NewFromRunner,最简洁,框架自动管理生命周期
- 适合大多数场景
2. ServiceRunner 函数式(快速原型):传入 func(ctx context.Context) error
- 使用 NewServiceRunner 创建,再用 New 构建 Service
- 无需定义类型,适合快速开发,支持自定义启动/停止逻辑
3. Interface 传统方式(向后兼容):实现 Start/Stop 方法
- 使用 New,需手动管理 goroutine 和退出信号
- 保留用于遗留代码
迁移指南(从传统 Interface 到 Runner):
传统方式(约 30 行):
type program struct {
quit chan struct{}
}
func (p *program) Start(s service.Service) error {
p.quit = make(chan struct{})
go p.run()
return nil
}
func (p *program) run() {
for {
select {
case <-p.quit:
return
default:
// 业务逻辑
}
}
}
func (p *program) Stop(s service.Service) error {
close(p.quit)
return nil
}
简化为 Runner 方式(约 10 行):
type program struct{}
func (p *program) Run(ctx context.Context) error {
for {
select {
case <-ctx.Done():
return nil
default:
// 业务逻辑
}
}
}
或使用 ServiceRunner(约 5 行):
runner := service.NewServiceRunner(func(ctx context.Context) error {
<-ctx.Done()
return nil
})
何时选择哪种方式:
- 新项目:优先使用 Runner 接口或 ServiceRunner
- 需要自定义启动/停止逻辑:使用 ServiceRunner.StartFunc/StopFunc
- 需要超时控制:设置 ServiceRunner.StartTimeout/StopTimeout
- 遗留代码:保持 Interface 方式,或渐进式迁移到 Runner
Windows controls services by setting up callbacks that is non-trivial. This is very different than other systems. This package provides the same API despite the substantial differences. It also can be used to detect how a program is called, from an interactive terminal or from a service manager.
高级示例(结构化依赖、超时及跨平台日志配置):
import "time"
func buildConfig() *service.Config {
return &service.Config{
Name: "myapp",
StructuredDeps: []service.Dependency{
{Name: "network.target", Type: service.DependencyAfter}, // systemd/launchd 会等待网络
{Name: "postgresql", Type: service.DependencyRequire}, // Windows/Systemd 映射为硬依赖
},
Timeout: service.TimeoutConfig{ // 0 使用各平台默认
Start: 30 * time.Second,
Stop: 20 * time.Second,
Restart: 5 * time.Second,
},
}
}
Linux 下可使用 GenerateLogrotateConfig 写入 /etc/logrotate.d/myapp, systemd 可将 GenerateSystemdJournalConfig 输出放到 /etc/systemd/journald.conf.d/, Windows 则可用 GenerateWindowsEventLogConfig 输出的 PowerShell 注册事件源。 平台未使用的配置安全忽略。
Example (RunnerBasic) ¶
Example_runnerBasic 展示使用 NewServiceRunner 快速构建服务。
package main
import (
"context"
"fmt"
"time"
service "github.com/darkit/daemon"
)
func main() {
runner := service.NewServiceRunner(func(ctx context.Context) error {
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
for i := 0; i < 3; i++ {
select {
case <-ticker.C:
fmt.Printf("tick %d\n", i+1)
case <-ctx.Done():
return nil
}
}
return nil
})
// 直接调用 RunFunc 模拟运行。
_ = runner.RunFunc(context.Background())
}
Output: tick 1 tick 2 tick 3
Example (RunnerInterface) ¶
Example_runnerInterface 展示实现 Runner 接口。
package main
import (
"context"
"fmt"
"time"
service "github.com/darkit/daemon"
)
type exampleRunner struct{}
func (exampleRunner) Run(ctx context.Context) error {
for i := 0; i < 3; i++ {
fmt.Printf("working %d\n", i+1)
time.Sleep(10 * time.Millisecond)
}
return nil
}
func main() {
var svc service.Runner = &exampleRunner{}
_ = svc.Run(context.Background())
}
Output: working 1 working 2 working 3
Example (RunnerWithTimeout) ¶
Example_runnerWithTimeout 展示自定义超时配置。
package main
import (
"context"
"fmt"
"time"
service "github.com/darkit/daemon"
)
func main() {
runner := service.NewServiceRunner(func(ctx context.Context) error {
<-ctx.Done()
return ctx.Err()
})
// 自定义超时
runner.StartTimeout = 5 * time.Second
runner.StopTimeout = 3 * time.Second
fmt.Println("配置完成")
}
Output: 配置完成
Index ¶
- Constants
- Variables
- func ChooseSystem(a ...System)
- func Control(s Service, action string) error
- func GenerateLogrotateConfig(name, logPath string) string
- func GenerateSystemdJournalConfig(name string) string
- func GenerateWindowsEventLogConfig(name, source string) string
- func Interactive() bool
- func Platform() string
- type Config
- type ControlsHandler
- type Dependency
- type DependencyType
- type Interface
- type KeyValue
- type Logger
- type Runner
- type Service
- type ServiceRunner
- type Shutdowner
- type Status
- type System
- type TimeoutConfig
Examples ¶
Constants ¶
const ( // OptionRestart systemd:控制重启策略,对应 unit Restart=。 OptionRestart = optionRestart // OptionRestartSec systemd:重启前延迟秒数,对应 RestartSec=。 OptionRestartSec = optionRestartSec // OptionStartLimitBurst systemd:限流窗口内允许的最大重启次数,对应 StartLimitBurst=。 OptionStartLimitBurst = "StartLimitBurst" // OptionStartLimitIntervalSec systemd:重启限流窗口长度(秒),对应 StartLimitIntervalSec=。 OptionStartLimitIntervalSec = "StartLimitIntervalSec" // OptionExecStartPre systemd:主进程启动前执行的命令钩子,对应 Service.ExecStartPre=。 OptionExecStartPre = optionExecStartPre // OptionExecStartPost systemd:主进程启动后执行的命令钩子,对应 Service.ExecStartPost=。 OptionExecStartPost = optionExecStartPost // OptionExecStopPost systemd:停止完成后的清理钩子,对应 Service.ExecStopPost=。 OptionExecStopPost = optionExecStopPost // OptionOnFailureUnit systemd:失败时要激活的 unit(Unit.OnFailure),与 Windows 的 OptionOnFailure(SCM 重启/重启机器/无动作恢复策略)语义不同。 OptionOnFailureUnit = optionOnFailureUnit // OptionOnFailure Windows:服务失败后的恢复动作。 OptionOnFailure = "OnFailure" // OptionOnFailureDelay Windows:服务失败后再次尝试前的延迟。 OptionOnFailureDelay = "OnFailureDelay" // OptionPreStartScript upstart:服务启动前执行的脚本,对应 pre-start script。 OptionPreStartScript = optionPreStartScript // OptionPostStopScript upstart:服务停止后执行的脚本,对应 post-stop script。 OptionPostStopScript = optionPostStopScript )
Option* 常量提供跨平台 Option Key,便于调用方避免硬编码字符串。
const ( ControlActionStart = "start" ControlActionStop = "stop" ControlActionRestart = "restart" ControlActionInstall = "install" ControlActionUninstall = "uninstall" )
ControlAction list valid string texts to use in Control.
Variables ¶
var ( // ErrNameFieldRequired is returned when Config.Name is empty. ErrNameFieldRequired = errors.New("Config.Name field is required.") //nolint:revive // ErrNoServiceSystemDetected is returned when no system was detected. ErrNoServiceSystemDetected = errors.New("No service system detected.") //nolint:revive // ErrNotInstalled is returned when the service is not installed. ErrNotInstalled = errors.New("the service is not installed") )
var ConsoleLogger = consoleLogger{} //nolint:gochecknoglobals
ConsoleLogger logs to the std err.
Functions ¶
func ChooseSystem ¶
func ChooseSystem(a ...System)
ChooseSystem chooses a system from the given system services. SystemServices are considered in the order they are suggested. Calling this may change what Interactive and Platform return.
func GenerateLogrotateConfig ¶
GenerateLogrotateConfig 返回 logrotate 配置片段,可直接写入 /etc/logrotate.d/<name>。 参数 name 用于推导默认日志路径(/var/log/<name>.log),logPath 留空时采用默认;仅 Linux/Unix 使用,其他平台可安全忽略。
func GenerateSystemdJournalConfig ¶
GenerateSystemdJournalConfig 生成 systemd journald 的 drop-in 片段,放置于 /etc/systemd/journald.conf.d/<name>.conf。 参数 name 作为日志目录名(默认 "service"),仅 systemd 上生效,非 systemd 平台调用后输出可忽略。
func GenerateWindowsEventLogConfig ¶
GenerateWindowsEventLogConfig 返回注册 Windows EventLog 源的 PowerShell 示例。 参数 name 为日志名称(默认 Application),source 为空时回退为 name;仅 Windows 有意义。
func Interactive ¶
func Interactive() bool
Interactive returns false if running under the OS service manager and true otherwise.
Types ¶
type Config ¶
type Config struct {
Name string // Required name of the service. No spaces suggested.
DisplayName string // Display name, spaces allowed.
Description string // Long description of service.
UserName string // Run as username.
Arguments []string // Run with arguments.
// Optional field to specify the executable for service.
// If empty the current executable is used.
Executable string
// Array of service dependencies.
// Not yet fully implemented on Linux or OS X:
// 1. Support linux-systemd dependencies, just put each full line as the
// element of the string array, such as
// "After=network.target syslog.target"
// "Requires=syslog.target"
// Note, such lines will be directly appended into the [Unit] of
// the generated service config file, will not check their correctness.
Dependencies []string
// StructuredDeps 使用 Dependency 定义跨平台依赖,优先于 Dependencies;空 Type 视为 DependencyAfter,
// Windows/systemd/OpenRC 完整支持,sysv/upstart/launchd 会忽略不支持的类型。
StructuredDeps []Dependency
// The following fields are not supported on Windows.
WorkingDirectory string // Initial working directory.
ChRoot string
// System specific options.
Option KeyValue
EnvVars map[string]string
// Timeout 配置启动、停止、重启的超时;0 使用平台默认,Restart 仅 systemd/upstart 生效。
Timeout TimeoutConfig
// AllowSudoFallback 仅在缺少 start-stop-daemon 等降权能力时使用 su,默认 false 保持历史行为。
AllowSudoFallback bool
}
Config provides the setup for a Service. The Name field is required.
func (*Config) GroupDependenciesByType ¶
GroupDependenciesByType 按依赖类型分组(字符串键),模板使用。
type ControlsHandler ¶
type ControlsHandler struct{}
ControlsHandler is a stub of windows specific helper for common code.
type Dependency ¶
type Dependency struct {
Name string // 依赖服务名称
Type DependencyType // 依赖类型
}
Dependency 定义结构化依赖项,Name 为目标服务名,Type 控制顺序/强度。
type DependencyType ¶
type DependencyType string
StructuredDeps 提供跨平台的结构化依赖管理,优先于字符串形式的 Dependencies。
优先级:StructuredDeps > Dependencies。
平台支持:
- Windows: 完整支持(映射到 SCM Dependencies)。
- systemd: 完整支持(After/Before/Requires/Wants)。
- OpenRC: 完整支持(need/use/before)。
- upstart: 部分支持(start on)。
- sysv: 部分支持(LSB 标签)。
- launchd: 实验性(轮询等待)。
示例:
cfg := &service.Config{
Name: "myapp",
StructuredDeps: []service.Dependency{
{Name: "network.target", Type: service.DependencyAfter},
{Name: "postgresql", Type: service.DependencyRequire},
},
}
DependencyType 描述依赖关系在不同平台上的语义映射,缺省值视为 DependencyAfter。
const ( // DependencyAfter 表示软顺序依赖,常映射为 systemd/launchd After 或 Windows 服务依赖。 DependencyAfter DependencyType = "after" // DependencyBefore 表示当前服务需在目标服务之前启动,映射为 systemd Before。 DependencyBefore DependencyType = "before" // DependencyRequire 表示硬依赖,目标服务不可用时当前服务启动失败,映射为 systemd Requires 或 Windows SCM 依赖。 DependencyRequire DependencyType = "require" // DependencyWant 表示推荐依赖,目标缺失时继续启动,映射为 systemd Wants。 DependencyWant DependencyType = "want" )
type Interface ¶
type Interface interface {
// Start provides a place to initiate the service. The service doesn't
// signal a completed start until after this function returns, so the
// Start function must not take more than a few seconds at most.
Start(s Service) error
// Stop provides a place to clean up program execution before it is terminated.
// It should not take more than a few seconds to execute.
// Stop should not call os.Exit directly in the function.
Stop(s Service) error
}
Interface represents the service interface for a program. Start runs before the hosting process is granted control and Stop runs when control is returned.
- OS service manager executes user program.
- User program sees it is executed from a service manager (IsInteractive is false).
- User program calls Service.Run() which blocks.
- Interface.Start() is called and quickly returns.
- User program runs.
- OS service manager signals the user program to stop.
- Interface.Stop() is called and quickly returns. - For a successful exit, os.Exit should not be called in Interface.Stop().
- Service.Run returns.
- User program should quickly exit.
type KeyValue ¶
type KeyValue map[string]interface{}
KeyValue provides a list of system specific options.
OS X
LaunchdConfig string () - Use custom launchd config.
KeepAlive bool (true) - Prevent the system from stopping the service automatically.
RunAtLoad bool (false) - Run the service after its job has been loaded.
SessionCreate bool (false) - Create a full user session.
Solaris
Prefix string ("application") - Service FMRI prefix.
POSIX
UserService bool (false) - Install as a current user service.
SystemdScript string () - Use custom systemd script.
UpstartScript string () - Use custom upstart script.
SysvScript string () - Use custom sysv script.
OpenRCScript string () - Use custom OpenRC script.
RunWait func() (wait for SIGNAL) - Do not install signal but wait for this function to return.
自定义函数内部使用 signal.NotifyContext 时,必须调用 defer stop() 清理资源
示例: func customWait() { ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM) defer stop() <-ctx.Done() }
ReloadSignal string () [USR1, ...] - Signal to send on reload.
PIDFile string () [/run/prog.pid] - Location of the PID file.
LogOutput bool (false) - Redirect StdErr & StandardOutPath to files.
Restart string (always) - How shall service be restarted.
SuccessExitStatus string () - The list of exit status that shall be considered as successful, in addition to the default ones.
LogDirectory string(/var/log) - The path to the log files directory
Linux (systemd)
LimitNOFILE int (-1) - Maximum open files (ulimit -n) (https://serverfault.com/questions/628610/increasing-nproc-for-processes-launched-by-systemd-on-centos-7)
Windows
DelayedAutoStart bool (false) - After booting, start this service after some delay.
Password string () - Password to use when interfacing with the system service manager.
Interactive bool (false) - The service can interact with the desktop. (more information https://docs.microsoft.com/en-us/windows/win32/services/interactive-services)
DelayedAutoStart bool (false) - after booting start this service after some delay.
StartType string ("automatic") - Start service type. (automatic | manual | disabled)
OnFailure string ("restart" ) - Action to perform on service failure. (restart | reboot | noaction)
OnFailureDelayDuration string ( "1s" ) - Delay before restarting the service, time.Duration string.
OnFailureResetPeriod int ( 10 ) - Reset period for errors, seconds.
PIDFile string () [/run/prog.pid] - Location of the PID file.
LogOutput bool (false) - Redirect StdErr & StandardOutPath to files.
Restart string (always) - How shall service be restarted.
SuccessExitStatus string () - The list of exit status that shall be considered as successful, in addition to the default ones.
LogDirectory string(/var/log) - The path to the log files directory
* Linux (systemd)
- LimitNOFILE int (-1) - Maximum open files (ulimit -n) (https://serverfault.com/questions/628610/increasing-nproc-for-processes-launched-by-systemd-on-centos-7)
* Windows
- DelayedAutoStart bool (false) - After booting, start this service after some delay.
- Password string () - Password to use when interfacing with the system service manager.
- Interactive bool (false) - The service can interact with the desktop. (more information https://docs.microsoft.com/en-us/windows/win32/services/interactive-services)
- DelayedAutoStart bool (false) - After booting start this service after some delay.
- StartType string ("automatic") - Start service type. (automatic | manual | disabled)
- OnFailure string ("restart" ) - Action to perform on service failure. (restart | reboot | noaction)
- OnFailureDelayDuration string ( "1s" ) - Delay before restarting the service, time.Duration string.
- OnFailureResetPeriod int ( 10 ) - Reset period for errors, seconds.
- ExtraControls ControlsHandler (nil, nil) - Handle controls other than Stop and Shutdown.
type Logger ¶
type Logger interface {
Error(v ...interface{}) error
Warning(v ...interface{}) error
Info(v ...interface{}) error
Errorf(format string, a ...interface{}) error
Warningf(format string, a ...interface{}) error
Infof(format string, a ...interface{}) error
}
Logger writes to the system log.
type Runner ¶
Runner 接口定义了简化的服务运行模型。 实现此接口的类型可以直接传递给 service.New,框架会自动将其包装为 ServiceRunner, ServiceRunner 再实现 Interface 接口,完成完整的生命周期适配。
生命周期通过 context 管理:
- Run 会在独立 goroutine 中执行
- ctx 被取消时应立刻返回
- 返回的 error 会被透传到 Service.Wait / Run
示例:
type MyService struct{}
func (s *MyService) Run(ctx context.Context) error {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
// 业务逻辑
case <-ctx.Done():
return ctx.Err()
}
}
}
type Service ¶
type Service interface {
// Run should be called shortly after the program entry point.
// After Interface.Stop has finished running, Run will stop blocking.
// After Run stops blocking, the program must exit shortly after.
Run() error
// Start signals to the OS service manager the given service should start.
Start() error
// Stop signals to the OS service manager the given service should stop.
Stop() error
// Restart signals to the OS service manager the given service should stop then start.
Restart() error
// Install setups up the given service in the OS service manager. This may require
// greater rights. Will return an error if it is already installed.
Install() error
// Uninstall removes the given service from the OS service manager. This may require
// greater rights. Will return an error if the service is not present.
Uninstall() error
// Opens and returns a system logger. If the user program is running
// interactively rather than as a service, the returned logger will write to
// os.Stderr. If errs is non-nil errors will be sent on errs as well as
// returned from Logger's functions.
Logger(errs chan<- error) (Logger, error)
// SystemLogger opens and returns a system logger. If errs is non-nil errors
// will be sent on errs as well as returned from Logger's functions.
SystemLogger(errs chan<- error) (Logger, error)
// String displays the name of the service. The display name if present,
// otherwise the name.
String() string
// Platform displays the name of the system that manages the service.
// In most cases this will be the same as service.Platform().
Platform() string
// Status returns the current service status.
Status() (Status, error)
}
Service represents a service that can be run or controlled.
type ServiceRunner ¶
type ServiceRunner struct {
// RunFunc 在独立 goroutine 中运行,当 ctx 取消时应退出。
// 如果同时设置了 StartFunc,则 RunFunc 优先级更高。
RunFunc func(ctx context.Context) error
// StartFunc 在服务启动时执行,应快速返回(类似 Interface.Start)。
// 通常用于初始化资源,实际工作在后台 goroutine 中进行。
StartFunc func(ctx context.Context) error
// StopFunc 在服务停止时执行,应快速清理资源(类似 Interface.Stop)。
StopFunc func(ctx context.Context) error
// StartTimeout 指定启动超时时间,默认 10 秒。
// 超时后返回 context.DeadlineExceeded。
StartTimeout time.Duration
// StopTimeout 指定停止超时时间,默认 10 秒。
// 超时后强制取消 context。
StopTimeout time.Duration
// contains filtered or unexported fields
}
ServiceRunner 提供函数式服务运行辅助,用于快速构建服务而无需定义完整类型。
支持两种使用模式:
- 仅提供 RunFunc:在独立 goroutine 中运行,Stop 时取消 context
- 提供 StartFunc + StopFunc:分别在启动和停止时执行自定义逻辑
超时配置:
- StartTimeout:启动超时(默认 10 秒)
- StopTimeout:停止超时(默认 10 秒)
示例 1(仅 RunFunc):
runner := &ServiceRunner{
RunFunc: func(ctx context.Context) error {
<-ctx.Done()
return nil
},
}
svc, _ := service.New(runner, cfg)
svc.Run()
示例 2(StartFunc + StopFunc):
runner := &ServiceRunner{
StartFunc: func(ctx context.Context) error {
// 初始化资源
return nil
},
StopFunc: func(ctx context.Context) error {
// 清理资源
return nil
},
}
func NewServiceRunner ¶
func NewServiceRunner(runFunc func(ctx context.Context) error) *ServiceRunner
NewServiceRunner 创建一个新的 ServiceRunner 实例。
参数:
- runFunc:主运行函数,在独立 goroutine 中执行
返回的 ServiceRunner 使用默认超时(启动和停止各 10 秒)。 可通过修改返回值的 StartTimeout 和 StopTimeout 字段自定义超时。
示例:
runner := service.NewServiceRunner(func(ctx context.Context) error {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
log.Println("tick")
case <-ctx.Done():
return nil
}
}
})
runner.StopTimeout = 5 * time.Second // 自定义停止超时
func (*ServiceRunner) Start ¶
func (r *ServiceRunner) Start(_ Service) error
Start 启动服务,实现 Interface.Start。 如果设置了 RunFunc,会在后台 goroutine 中运行;如果设置了 StartFunc,会在当前 goroutine 中执行。
func (*ServiceRunner) Stop ¶
func (r *ServiceRunner) Stop(_ Service) error
Stop 停止服务,实现 Interface.Stop。 取消 context 并等待 RunFunc 退出或执行 StopFunc。
type Shutdowner ¶
type Shutdowner interface {
Interface
// Shutdown provides a place to clean up program execution when the system is being shutdown.
// It is essentially the same as Stop but for the case where machine is being shutdown/restarted
// instead of just normally stopping the service. Stop won't be called when Shutdown is.
Shutdown(s Service) error
}
Shutdowner represents a service interface for a program that differentiates between "stop" and "shutdown". A shutdown is triggered when the whole box (not just the service) is stopped.
type System ¶
type System interface {
// String returns a description of the system.
String() string
// Detect returns true if the system is available to use.
Detect() bool
// Interactive returns false if running under the system service manager
// and true otherwise.
Interactive() bool
// New creates a new service for this system.
New(i Interface, c *Config) (Service, error)
}
System represents the service manager that is available.
func AvailableSystems ¶
func AvailableSystems() []System
AvailableSystems returns the list of system services considered when choosing the system service.
func ChosenSystem ¶
func ChosenSystem() System
ChosenSystem returns the system that service will use.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
example
|
|
|
advanced
command
高级示例:展示 StructuredDeps、TimeoutConfig 与生命周期钩子用法。
|
高级示例:展示 StructuredDeps、TimeoutConfig 与生命周期钩子用法。 |
|
logging
command
Simple service that only works by printing a log message every few seconds.
|
Simple service that only works by printing a log message every few seconds. |
|
runner
command
Simple service that only works by printing a log message every few seconds.
|
Simple service that only works by printing a log message every few seconds. |
|
simple
command
simple does nothing except block while running the service.
|
simple does nothing except block while running the service. |
|
stopPause
command
simple does nothing except block while running the service.
|
simple does nothing except block while running the service. |