Add support for input plane invocation#32
Conversation
291fad9 to
de7c480
Compare
57703ea to
0ce79ee
Compare
cacbb31 to
23a98f7
Compare
0ce79ee to
f65d93e
Compare
a998493 to
48296fb
Compare
75afd74 to
55e27f0
Compare
48296fb to
02763e7
Compare
55e27f0 to
eb9fcc6
Compare
02763e7 to
7bc2d75
Compare
a999ab3 to
99f9f77
Compare
7bc2d75 to
14f9d4f
Compare
a38d9c2 to
90b362b
Compare
14f9d4f to
56efc9b
Compare
4d45866 to
23652f8
Compare
|
The PR this was based on has been merged to main. This PR has been rebased on main, and is ready for review. |
| import { ClientType, ModalClientDefinition } from "../proto/modal_proto/api"; | ||
| import { type Profile, profile } from "./config"; | ||
|
|
||
| let modalAuthToken: string | undefined; |
There was a problem hiding this comment.
This is a global variable right now and will end up shared between multiple clients. Instead I think it needs to be declared in the authMiddleware() factory between line 19 function authMiddleware(...) and line 20 return async function* authMiddleware(...), so it doesn't end up becoming accidentally shared global state.
There was a problem hiding this comment.
We actually intentionally share the token between the control plane client and the input plane client. Here's the flow:
- We call the control plane, and do not specify an auth token (because we don't have one yet)
- The control plane sees there is no auth token - so it generates one, and returns it to the client
- The client the specifies that auth token in every subsequent request to both the control plane and the input plane.
I will add a comment explaining this.
modal-js/src/client.ts
Outdated
| if (prevOnHeader) { | ||
| prevOnHeader(header); | ||
| } |
modal-js/src/invocation.ts
Outdated
| } catch (err) { | ||
| throw new Error(`FunctionGetOutputs failed: ${err}`); | ||
| } |
There was a problem hiding this comment.
I don't think we should catch this error this way since it erases the error details and status code from the structured Status response, and turns it into a string. Also the grpc error already has the method name in the stack, so this isn't necessary.
My thought process on errors is, in theory we would have every single possible turn into a human-readable format that is intelligible to users. In practice there are a lot of unanticipated, and the set of actual errors that users experience in practice is much smaller and more tractable to manage — so we let errors propagate by default, and we catch errors strategically based on which ones are actually expected to happen from library use (NotFoundError when you get the name of a function wrong, OutputExpired when you poll too late, etc.) and make them public API instead of an opaque Error type.
There was a problem hiding this comment.
Sounds reasonable to me! Will remove the catch.
|
|
||
| @app.function(min_containers=1, experimental_options={"input_plane_region": "us-west"}) | ||
| def input_plane(s: str) -> str: | ||
| return "output: " + s |
There was a problem hiding this comment.
nit: can you keep formatting with black?
modal-js/src/invocation.ts
Outdated
| /** | ||
| * Signature of a function that fetches a single output. Used by `pollForOutputs` to fetch from either | ||
| * the control plane or the input plane, depending on the implementation. | ||
| */ | ||
| type GetOutput = ( | ||
| timeoutMillis: number, | ||
| ) => Promise<FunctionGetOutputsItem | undefined>; |
There was a problem hiding this comment.
I think if we make a limited utility type like this that's used in one place, we should define it next to where it's used in pollFunctionOutput().
The documentation/naming on this method and type pollFunctionOutput() and GetOutput could be improved. It's not clear that what it's actually doing right now is, wrapping an output fetcher that's limited to the outputsTimeout constant (55 s) with a loop and continued polling so that it takes any timeout.
Also the naming is different between Go and JS of the interface, the identifiers called awaitOutput() / GetOutput / pollFunctionOutput() in JS correspond to getOutput() / getOutput / pollFunctionOutput() in Go, which is a bit confusing too because of the double-naming.
modal-go/function.go
Outdated
| // Attach x-modal-auth-token to all future requests. | ||
| authTokenArray := header.Get("x-modal-auth-token") | ||
| if len(authTokenArray) == 0 { | ||
| authTokenArray = trailer.Get("x-modal-auth-token") | ||
| } | ||
| if len(authTokenArray) > 0 { | ||
| authToken := authTokenArray[0] | ||
| ctx = metadata.AppendToOutgoingContext(ctx, "x-modal-auth-token", authToken) | ||
| } |
There was a problem hiding this comment.
Also isn't this middleware implementation … different from how x-modal-auth-token is being handled in modal-js? One of them will save auth tokens per client/globally, and one will save per function. I think it's really important that we try to make the client libraries behave the same way.
There was a problem hiding this comment.
Sounds good. I will update the go code to match the typescript.
c3bcd2d to
90673b6
Compare
f1f43a9 to
9fff513
Compare
1315218 to
3635731
Compare
3635731 to
c8fe4fb
Compare
|
I addressed the PR comments, so this is ready for another review! |
modal-js/src/invocation.ts
Outdated
| }); | ||
| return response.output; | ||
| } catch (err) { | ||
| throw new Error(`AttemptAwait failed: ${err}`); |
There was a problem hiding this comment.
This should maybe also not be caught, with similar reasoning as #32 (comment)?
There was a problem hiding this comment.
Ah, yes! I pushed another commit removing that.
79ff102 to
1b26949
Compare
|
Yes, and sorry for any delays! |
* Add support for input plane * Address PR review comments * Remove catch
This is based on #31.This PR adds a new
InputPlaneInvocationclass, which sends inputs to the input plane, rather than the control plane. This will be used only for function definitions which include theinput_plane_regionexperimental option like this:If not specified, the
ControlPlaneInvocationwill be used.For now this includes only the typescript implementation - if this approach looks good, we will add the go implementation.