Skip to content

Commit a3a63b1

Browse files
h4x3rotabclaude
andcommitted
chore(consul-postgres-ha): env-gated pion ICE debug logs (MESH_CONN_DEBUG_ICE)
Plumbed `mesh_conn_debug_ice` from terraform.tfvars through cluster.tf + both compose templates + entrypoint into mesh-conn, where setting the env to "1" wires `logging.NewDefaultLoggerFactory()` at LogLevelTrace into pion's ice.AgentConfig. Used to diagnose the post-hot-patch worker↔coord ICE-failure mode (see findings below). Off by default — the trace output is very chatty. Findings from one full instrumented run on the live cluster: - pion's outbound STUN BINDING_REQUESTs are sent normally over the TURN allocation (~1Hz to each candidate pair). - ZERO inbound STUN ever arrives at the workers' pion after a sidecar restart. `agent.go:1092 Inbound STUN` log line never appears in worker-3's log; eventually pion logs `Maximum requests reached for pair ... marking it as failed` and the agent gives up. - Coordinators' pion DOES receive inbound STUN (from workers, in fact) and successfully NOMINATE candidate pairs — coord-0 logged `selected pair: relay 155.138.146.255:49666 <-> relay 155.138.146.255:49456 (proto=udp)` for [worker-3] within ~3s of worker-3 republishing post-restart. So the path is genuinely half-open: worker→coord traffic flows, coord→worker doesn't. - coturn shows zero rejections / quota / permission errors throughout. Allocation count rises and falls cleanly. - All 6 CVMs share the same public IP (66.220.6.107 = dstack provider NAT). Different per-CVM source ports. Conclusion: the asymmetric inbound-UDP failure is at the dstack edge NAT, not at mesh-conn or coturn. Workers post-restart can't receive inbound UDP from the relay on coturn's high port range (155.138.146.255:49152-49999), even though coordinators on the same cluster can. This is likely a NAT-mapping lifecycle issue (the new post-restart mapping permits coturn:3478 source but not the coturn:relay-port source), but proving that needs platform-side inspection that we don't have access to. Approach 2 (the partial fix in 5548bab) catches the stale-auth race when it does fire, but the underlying inbound-UDP-blocked condition prevents convergence regardless. The fix stays in (catches a real race, doesn't make anything worse); the dstack-platform UDP behavior needs a separate investigation and fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cc5a12d commit a3a63b1

5 files changed

Lines changed: 25 additions & 3 deletions

File tree

consul-postgres-ha/cluster-example/cluster.tf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ variable "mesh_conn_relay_only" {
110110
default = ""
111111
}
112112

113+
# Set to "1" to enable pion's verbose ICE debug logs (connectivity
114+
# checks, STUN attribute parsing). Useful when debugging hot-patch
115+
# / re-handshake flakiness; off by default because it's very chatty.
116+
variable "mesh_conn_debug_ice" {
117+
type = string
118+
default = ""
119+
}
120+
113121
# ---------- Cluster topology + VIP allocation ----------
114122

115123
locals {
@@ -188,6 +196,7 @@ resource "phala_app" "coordinator" {
188196
# Stage-1 WORKAROUND — see `random_bytes` block at top of file.
189197
GOSSIP_KEY = random_bytes.gossip_key.base64
190198
MESH_CONN_RELAY_ONLY = var.mesh_conn_relay_only
199+
MESH_CONN_DEBUG_ICE = var.mesh_conn_debug_ice
191200
}
192201

193202
listed = false
@@ -233,6 +242,7 @@ resource "phala_app" "worker" {
233242
PATRONI_SUPERUSER_PW = random_bytes.patroni_superuser_pw.hex
234243
PATRONI_REPLICATION_PW = random_bytes.patroni_replication_pw.hex
235244
MESH_CONN_RELAY_ONLY = var.mesh_conn_relay_only
245+
MESH_CONN_DEBUG_ICE = var.mesh_conn_debug_ice
236246
}
237247

238248
listed = false

consul-postgres-ha/compose/coordinator.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ services:
6060
- GOSSIP_KEY=${GOSSIP_KEY}
6161
# See worker.yaml for the rationale on MESH_CONN_RELAY_ONLY.
6262
- MESH_CONN_RELAY_ONLY=${MESH_CONN_RELAY_ONLY:-}
63+
- MESH_CONN_DEBUG_ICE=${MESH_CONN_DEBUG_ICE:-}
6364
volumes:
6465
- /var/run/dstack.sock:/var/run/dstack.sock:ro
6566
- /tmp/dstack-runtime/secrets:/run/secrets

consul-postgres-ha/compose/worker.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ services:
4848
# Default off because direct candidates work; flip on if a
4949
# deployment hits worker↔worker direct-pair instability.
5050
- MESH_CONN_RELAY_ONLY=${MESH_CONN_RELAY_ONLY:-}
51+
- MESH_CONN_DEBUG_ICE=${MESH_CONN_DEBUG_ICE:-}
5152
volumes:
5253
- /var/run/dstack.sock:/var/run/dstack.sock:ro
5354
- /tmp/dstack-runtime/secrets:/run/secrets

consul-postgres-ha/mesh-conn/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.24
44

55
require (
66
github.com/pion/ice/v2 v2.3.25
7+
github.com/pion/logging v0.2.2
78
github.com/pion/stun v0.6.1
89
github.com/quic-go/quic-go v0.59.0
910
)
@@ -12,7 +13,6 @@ require (
1213
github.com/davecgh/go-spew v1.1.1 // indirect
1314
github.com/google/uuid v1.3.1 // indirect
1415
github.com/pion/dtls/v2 v2.2.7 // indirect
15-
github.com/pion/logging v0.2.2 // indirect
1616
github.com/pion/mdns v0.0.12 // indirect
1717
github.com/pion/randutil v0.1.0 // indirect
1818
github.com/pion/transport/v2 v2.2.2 // indirect

consul-postgres-ha/mesh-conn/main.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import (
8181
"time"
8282

8383
"github.com/pion/ice/v2"
84+
"github.com/pion/logging"
8485
"github.com/pion/stun"
8586
"github.com/quic-go/quic-go"
8687
)
@@ -919,11 +920,20 @@ func dialICE(cfg *Config, remoteID string) (*ice.Conn, error) {
919920
if os.Getenv("MESH_CONN_RELAY_ONLY") == "1" {
920921
candidateTypes = []ice.CandidateType{ice.CandidateTypeRelay}
921922
}
922-
agent, err := ice.NewAgent(&ice.AgentConfig{
923+
// MESH_CONN_DEBUG_ICE=1 turns on pion's verbose ICE-level logging
924+
// (connectivity-check requests/responses, STUN attribute parsing,
925+
// candidate-pair scoring). Off by default because it's chatty.
926+
agentCfg := &ice.AgentConfig{
923927
Urls: urls,
924928
NetworkTypes: []ice.NetworkType{ice.NetworkTypeUDP4, ice.NetworkTypeTCP4},
925929
CandidateTypes: candidateTypes,
926-
})
930+
}
931+
if os.Getenv("MESH_CONN_DEBUG_ICE") == "1" {
932+
lf := logging.NewDefaultLoggerFactory()
933+
lf.DefaultLogLevel = logging.LogLevelTrace
934+
agentCfg.LoggerFactory = lf
935+
}
936+
agent, err := ice.NewAgent(agentCfg)
927937
if err != nil {
928938
return nil, fmt.Errorf("NewAgent: %w", err)
929939
}

0 commit comments

Comments
 (0)