Skip to content

Commit 5846bcd

Browse files
committed
Wait for functions to become ready
When a function is newly deployed or updated folks will see a few connection refused errors in their XR. This setting may help with that by telling Crossplane to wait for the function to become ready rather than immediately returning an error. This commit also removes the 10 second timeouts for dialing and running a function. gRPC no longer recommends using DialContext. Instead they recommend using NewClient, which doesn't actually create a connection and thus doesn't need a timeout. Instead of a 10 second timeout to run the function, RunFunction now just uses the parent context's timeout which happens to be 2 minutes. This means the entire function pipeline (technically the entire XR reconcile) must complete within 2 minutes. This allows some functions to take a bit longer as long as the total runtime is within the timeout. Signed-off-by: Nic Cope <[email protected]>
1 parent ea5d796 commit 5846bcd

File tree

1 file changed

+24
-21
lines changed

1 file changed

+24
-21
lines changed

internal/xfn/function_runner.go

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,28 @@ const (
5050
errFmtDialFunction = "cannot gRPC dial target %q from status.endpoint of active FunctionRevision %q"
5151
)
5252

53-
// TODO(negz): Should any of these be configurable?
54-
const (
55-
// This configures a gRPC client to use round robin load balancing. This
56-
// means that if the Function Deployment has more than one Pod, and the
57-
// Function Service is headless, requests will be spread across each Pod.
58-
// See https://github.com/grpc/grpc/blob/v1.58.0/doc/load-balancing.md#load-balancing-policies
59-
lbRoundRobin = `{"loadBalancingConfig":[{"round_robin":{}}]}`
60-
61-
dialFunctionTimeout = 10 * time.Second
62-
runFunctionTimeout = 10 * time.Second
63-
)
53+
// This configures a gRPC client to use round robin load balancing. This means
54+
// that if the Function Deployment has more than one Pod, and the Function
55+
// Service is headless, requests will be spread across each Pod.
56+
// See https://github.com/grpc/grpc/blob/v1.58.0/doc/load-balancing.md#load-balancing-policies
57+
//
58+
// It also configures the gRPC client to wait for the server to be ready before
59+
// sending RPCs. Notably this gives Functions time to start before we make a
60+
// request. See https://grpc.io/docs/guides/wait-for-ready/
61+
const svcConfig = `
62+
{
63+
"loadBalancingConfig": [
64+
{
65+
"round_robin":{}
66+
}
67+
],
68+
"methodConfig": [
69+
{
70+
"name": [{}],
71+
"waitForReady": true
72+
}
73+
]
74+
}`
6475

6576
// A PackagedFunctionRunner runs a Function by making a gRPC call to a Function
6677
// package's runtime. It creates a gRPC client connection for each Function. The
@@ -136,10 +147,6 @@ func (r *PackagedFunctionRunner) RunFunction(ctx context.Context, name string, r
136147
return nil, errors.Wrapf(err, errFmtGetClientConn, name)
137148
}
138149

139-
// This context is used for actually making the request.
140-
ctx, cancel := context.WithTimeout(ctx, runFunctionTimeout)
141-
defer cancel()
142-
143150
rsp, err := NewBetaFallBackFunctionRunnerServiceClient(conn).RunFunction(ctx, req)
144151
return rsp, errors.Wrapf(err, errFmtRunFunction, name)
145152
}
@@ -220,18 +227,14 @@ func (r *PackagedFunctionRunner) getClientConn(ctx context.Context, name string)
220227
delete(r.conns, name)
221228
}
222229

223-
// This context is only used for setting up the connection.
224-
ctx, cancel := context.WithTimeout(ctx, dialFunctionTimeout)
225-
defer cancel()
226-
227230
is := make([]grpc.UnaryClientInterceptor, len(r.interceptors))
228231
for i := range r.interceptors {
229232
is[i] = r.interceptors[i].CreateInterceptor(name, active.Spec.Package)
230233
}
231234

232-
conn, err := grpc.DialContext(ctx, active.Status.Endpoint, //nolint:staticcheck // Figure out how to replace deprecated grpc.DialContext with grpc.NewClient and still pass the dialFunctionTimeout.
235+
conn, err := grpc.NewClient(active.Status.Endpoint,
233236
grpc.WithTransportCredentials(r.creds),
234-
grpc.WithDefaultServiceConfig(lbRoundRobin),
237+
grpc.WithDefaultServiceConfig(svcConfig),
235238
grpc.WithChainUnaryInterceptor(is...))
236239
if err != nil {
237240
return nil, errors.Wrapf(err, errFmtDialFunction, active.Status.Endpoint, active.GetName())

0 commit comments

Comments
 (0)