fix(bitrix24): mount shared webhook route independent of bot readiness [B24:2794] (#1432)

/bitrix24/* only mounted when a bitrix24 Channel loaded successfully via
WebhookHandlers(), which requires portal + bot_code + bot_name already
set. But completing portal OAuth requires /bitrix24/install to be
reachable, and the UI won't let you pick an uninstalled portal when
creating a bot -- deadlock on any fresh deployment: no bot can load
until OAuth completes, OAuth can't complete without the route mounted.

Claim and mount the shared bitrix24.WebhookRouter() singleton directly
at boot, independent of whether any Channel loaded. ClaimWebhookRoute
is idempotent (first-claim-wins via CompareAndSwap), so this is a
no-op once a real Channel has already claimed the route.

Co-authored-by: DangTinh311 <dangtinh31193@gmail.com>
This commit is contained in:
SYNITYandDangTinh311 authored and GitHub committed 2026-07-13 08:25:59 +07:00
1 parent 143ed4a8a4
commit 6167a53bbe
1 file changed
+16
+16
View File
@@ -10,6 +10,7 @@ import (
"github.com/nextlevelbuilder/goclaw/internal/bus"
"github.com/nextlevelbuilder/goclaw/internal/cache"
"github.com/nextlevelbuilder/goclaw/internal/channels"
"github.com/nextlevelbuilder/goclaw/internal/channels/bitrix24"
"github.com/nextlevelbuilder/goclaw/internal/config"
"github.com/nextlevelbuilder/goclaw/internal/edition"
"github.com/nextlevelbuilder/goclaw/internal/heartbeat"
@@ -259,6 +260,21 @@ func (d *gatewayDeps) runLifecycle(
slog.Info("webhook route mounted on gateway", "path", route.Path)
}
// Bitrix24: also claim+mount the shared webhook router directly, even if
// no channel_instances row has finished setup yet (bot_code/bot_name
// still empty, or the portal hasn't completed OAuth). /bitrix24/install
// is what completes portal OAuth — gating the route behind a
// fully-configured bot creates a deadlock where an admin can never
// finish installing the first portal on a fresh gateway. ClaimWebhookRoute
// is idempotent (first-claim-wins via CompareAndSwap), so this is a no-op
// if a bitrix24 Channel already claimed the route in the loop above.
if router := bitrix24.WebhookRouter(); router != nil {
if path, handler := router.ClaimWebhookRoute(); path != "" && handler != nil {
mux.Handle(path, handler)
slog.Info("webhook route mounted on gateway", "path", path)
}
}
tsCleanup := initTailscale(ctx, d.cfg, mux)
if tsCleanup != nil {
defer tsCleanup()