Skip to content

Commit 0832844

Browse files
committed
fixes
1 parent f31911b commit 0832844

3 files changed

Lines changed: 48 additions & 18 deletions

File tree

‎cmds/core-service/main.go‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,17 @@ func createAuxServer(ctx context.Context, locality string, publicEndpoint string
112112
return nil, stacktrace.Propagate(err, "Unable to interact with store")
113113
}
114114

115-
err = repo.SaveOwnMetadata(ctx, locality, publicEndpoint)
115+
// SaveOwnMetadata is proposed at startup, before any HTTP request exists, so the
116+
// context has neither a request timestamp nor a request seed (normally set by the
117+
// HTTP middleware). Stamp both: the proposal carries them to all nodes so that
118+
// every node derives the same time- and seed-dependent values when applying it.
119+
seed, err := random.NewSeed()
120+
if err != nil {
121+
return nil, stacktrace.Propagate(err, "failed to generate request seed")
122+
}
123+
metaCtx := random.NewContext(timestamp.WithRequestTimestamp(ctx, time.Now()), seed)
124+
125+
err = repo.SaveOwnMetadata(metaCtx, locality, publicEndpoint)
116126

117127
if err != nil {
118128
return nil, stacktrace.Propagate(err, "Unable to store current metadata")

‎deploy/services/helm-charts/dss/templates/dss-raft.yaml‎

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ metadata:
4040
name: {{.Release.Name}}-core-service
4141
name: {{.Release.Name}}-core-service
4242
spec:
43+
# All nodes must start together: each node blocks at startup on its first proposal
44+
# (its own metadata), which needs a quorum, and the HTTP server only starts once the
45+
# stores are initialized. With the default OrderedReady policy, pod-0 could never
46+
# become ready before pods 1..N start, deadlocking the bootstrap.
47+
podManagementPolicy: Parallel
4348
minReadySeconds: 30
4449
serviceName: {{.Release.Name}}-core-service-headless
4550
replicas: {{ $raft.replicas }}
@@ -68,38 +73,38 @@ spec:
6873
exec core-service \
6974
--accepted_jwt_audiences={{$dss.conf.hostname}} \
7075
--addr=:8080 \
71-
{{ if $dss.conf.publicEndpoint }}
76+
{{- if $dss.conf.publicEndpoint }}
7277
--public_endpoint={{$dss.conf.publicEndpoint}} \
73-
{{ end }}
78+
{{- end }}
7479
--locality={{$dss.conf.locality}} \
7580
--store_type=raft \
7681
--raft_node_id=$(( ${HOSTNAME##*-} + {{ $raft.nodeIDBase }} )) \
7782
--raft_cluster_id={{ $raft.clusterID }} \
7883
--raft_datadir={{ $raft.datadir }} \
79-
{{ range $flag, $value := $raft.tuning }}
84+
{{- range $flag, $value := $raft.tuning }}
8085
--{{ $flag }}={{ $value }} \
81-
{{ end }}
86+
{{- end }}
8287
--rid_raft_peers='{{ $ridPeers }}' \
8388
--scd_raft_peers='{{ $scdPeers }}' \
8489
--aux_raft_peers='{{ $auxPeers }}' \
8590
--enable_scd={{$dss.conf.enableScd}} \
8691
--enable_scd_global_lock={{$dss.conf.enableScdGlobalLock | default false}} \
87-
{{ if $dss.conf.enableTimeBasedNotificationIndex }}
92+
{{- if $dss.conf.enableTimeBasedNotificationIndex }}
8893
--enable_time_based_notification_index=true \
89-
{{ end }}
90-
{{ if $dss.conf.enableDssMetrics }}
94+
{{- end }}
95+
{{- if $dss.conf.enableDssMetrics }}
9196
--enable_metrics=true \
92-
{{ end }}
97+
{{- end }}
9398
--gcp_prof_service_name= \
94-
{{ if $dss.conf.jwksEndpoint }}
99+
{{- if $dss.conf.jwksEndpoint }}
95100
--jwks_endpoint={{ $dss.conf.jwksEndpoint }} \
96-
{{ end }}
97-
{{ if $dss.conf.jwksKeyIds }}
101+
{{- end }}
102+
{{- if $dss.conf.jwksKeyIds }}
98103
--jwks_key_ids={{ $dss.conf.jwksKeyIds | join "," }} \
99-
{{ end }}
100-
{{ if $dss.conf.pubKeys }}
104+
{{- end }}
105+
{{- if $dss.conf.pubKeys }}
101106
--public_key_files={{ $dss.conf.pubKeys | join "," }} \
102-
{{ end }}
107+
{{- end }}
103108
image: {{ $dss.image }}
104109
imagePullPolicy: {{ $dss.imagePullPolicy | default "Always" }}
105110
ports:
@@ -115,22 +120,31 @@ spec:
115120
name: raft-rid
116121
- containerPort: {{ $raft.ports.scd }}
117122
name: raft-scd
123+
# TCP probe on the first Raft listener (aux): the transport is up as soon as
124+
# the node is initialized, i.e. before it blocks on its first proposal
125+
# (which needs a quorum). Readiness must not depend on quorum: headless
126+
# services only publish DNS records for Ready pods, and peers are reached
127+
# through exactly those records, so a /healthy-based readiness would
128+
# deadlock the bootstrap (no quorum -> not ready -> no DNS -> no quorum).
118129
readinessProbe:
119-
httpGet:
120-
path: /healthy
121-
port: 8080
130+
tcpSocket:
131+
port: raft-aux
122132
resources:
123133
{{ toYaml $raft.resources | indent 12 }}
124134
stdin: false
125135
tty: false
126136
volumeMounts:
127137
- mountPath: {{ $raft.datadir }}
128138
name: raft-data
139+
{{- if $dss.conf.pubKeys }}
129140
{{- include "public-certs:volumeMount" (dict "cockroachdbEnabled" false) | nindent 12 }}
141+
{{- end }}
130142
imagePullSecrets: []
131143
terminationGracePeriodSeconds: 30
144+
{{- if $dss.conf.pubKeys }}
132145
volumes:
133146
{{- include "public-certs:volume" (dict "cockroachdbEnabled" false) | nindent 8 }}
147+
{{- end }}
134148
volumeClaimTemplates:
135149
- metadata:
136150
name: raft-data

‎pkg/random/random.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ func newSeed() (int64, error) {
2626
return int64(binary.BigEndian.Uint64(buf[:])), nil
2727
}
2828

29+
// NewSeed returns a fresh random seed. The HTTP middleware stamps every request with one;
30+
// proposals submitted outside of a request (e.g. at startup) must be stamped by the caller.
31+
func NewSeed() (int64, error) {
32+
return newSeed()
33+
}
34+
2935
// MustFromContext returns the request seed from the context and panics if it is not present,
3036
// which is a programming error.
3137
func MustFromContext(ctx context.Context) int64 {

0 commit comments

Comments
 (0)