feat: opencode serve — постоянный сервер вместо разовых subprocess (вариант A)
Супервайзер Server spawn'ит opencode serve (или ходит на внешний URL),
Runner ходит к нему через 'opencode run --attach <url>'. По умолчанию
serve.enabled=false — историческая spawn-модель сохранена; наличие
serve.url переключает на внешний сервер.
- config: ServeCfg (enabled/hostname/port/url/password) + дефолты; лоадер
научился int/bool (раньше только string/Duration/struct).
- opencode: Server (Start/Run/Close, /global/health, рестарт упавшего,
reaper-горутина владеет Wait; .Exited() непригоден для SIGKILL).
- Runner.AttachURL: run --attach <url> при заданном URL, иначе как раньше.
- app: composition root — при включённом serve запускает супервайзер.
- тесты: TestRun_AttachMode, TestServer_{ExternalURL,OwnProcess,Restart}.
This commit is contained in:
@@ -60,6 +60,7 @@ type App struct {
|
||||
Worker *worker.Worker
|
||||
Updater *update.Updater
|
||||
tg *telegram.Channel // сохранена для Run
|
||||
serve *opencode.Server // супервайзер opencode serve (режим --attach); nil, если выключен
|
||||
}
|
||||
|
||||
// New читает конфиг и собирает все зависимости.
|
||||
@@ -114,6 +115,25 @@ func New(configPath, version, updateToken string) (*App, error) {
|
||||
Stdout: os.Stderr,
|
||||
}
|
||||
|
||||
// Режим opencode serve (--attach): супервайзер держит постоянный сервер и
|
||||
// подключает Runner к нему. Включается serve.enabled (свой процесс) либо
|
||||
// serve.url (внешний). Выключено по умолчанию — прежняя spawn-модель.
|
||||
var serveSrv *opencode.Server
|
||||
if cfg.OpenCode.Serve.Enabled || cfg.OpenCode.Serve.URL != "" {
|
||||
serveSrv = &opencode.Server{
|
||||
Bin: cfg.OpenCode.Bin,
|
||||
DBPath: cfg.OpenCode.DBPath,
|
||||
Config: cfg.OpenCode.Config,
|
||||
ConfigDir: cfg.OpenCode.ConfigDir,
|
||||
Host: cfg.OpenCode.Serve.Hostname,
|
||||
Port: cfg.OpenCode.Serve.Port,
|
||||
Password: cfg.OpenCode.Serve.Password,
|
||||
URL: cfg.OpenCode.Serve.URL,
|
||||
Stdout: os.Stderr,
|
||||
}
|
||||
ocRunner.AttachURL = serveSrv.Addr()
|
||||
}
|
||||
|
||||
// Analyst (Decider)
|
||||
analystCtx := &analyst.Analyst{
|
||||
Runner: ocRunner,
|
||||
@@ -132,6 +152,7 @@ func New(configPath, version, updateToken string) (*App, error) {
|
||||
Config: cfg,
|
||||
Store: store,
|
||||
CoreCtx: coreCtx,
|
||||
serve: serveSrv,
|
||||
}
|
||||
router := chat.NewRouter(a.handleIncoming)
|
||||
|
||||
@@ -185,6 +206,17 @@ func (a *App) Run(ctx context.Context) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
// opencode serve: поднимаем супервайзер до старта воркера (иначе первый
|
||||
// вызов --attach упрётся в несуществующий сервер). При неудаче — не стартуем.
|
||||
if a.serve != nil {
|
||||
if err := a.serve.Start(ctx); err != nil {
|
||||
return fmt.Errorf("opencode serve: %w", err)
|
||||
}
|
||||
log.Printf("app: opencode serve up at %s (attach mode)", a.serve.Addr())
|
||||
go a.serve.Run(ctx)
|
||||
defer a.serve.Close()
|
||||
}
|
||||
|
||||
// Канал для проверки Telegram-ошибки (горутина оборачивает Run)
|
||||
tgErr := make(chan error, 1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user