> > What does "SomeOtherFunc" need with the statefun context > > I think it's hard to answer this question, in a general sense. Depending > on what is being done, it might need to read a value from statefun Storage, > write one back, etc.
To me, this indicates that the context is responsible for too much and cannot properly be passed to functions with a distinct purpose. I think the `context.Context` shares this design but gets away with it because its functionality is so constrained and generic (deadlines, cancellation, values – that's it). This is getting away from the original question of the thread, but I bring it up to suggest that we take a more holistic look at the statefun Context interface and go with a simpler solution (either the `WithContext` method or Till's suggestion) to avoid further muddying the possible uses. WDYT? Austin On Tue, Feb 22, 2022 at 1:14 PM Galen Warren <ga...@cvillewarrens.com> wrote: > One place we could look is the `net/http` Request, which has a >> `WithContext` method[1] that seems to expose the behavior we're looking >> for. >> > > I considered something similar, too, and upon another look, maybe I > dismissed it too quickly. The concern I had was that an implementation that > simply updated the internal context.Context of an existing statefun.Context > would violate the assumption that contexts are immutable. However, if the > implementation copied all the statefun.Context parts to a new stateful > context structure and associated them with the passed-in context.Context, > that seems like it could work. There's a sync.Mutex in the statefun context > structure that we'd have to be careful about. > > >> What does "SomeOtherFunc" need with the statefun context? >> > > I think it's hard to answer this question, in a general sense. Depending > on what is being done, it might need to read a value from statefun Storage, > write one back, etc. > > The solution that Till proposed seems to fit the example you gave quite >> well, no? >> > > Yes, this would work, but I agree with Till that this is not a perfect > solution. In the event that downstream code needs to access both the > context.Context and the statefun.Context, one would be passing two contexts > around, but it would be important not to use the statefun.Context one for > any context values. That's workable, but it seems a bit clumsy to me. > > On Tue, Feb 22, 2022 at 12:47 PM Austin Cawley-Edwards < > austin.caw...@gmail.com> wrote: > >> Hey, >> >> Sorry for the late response – been off the ML for a few days. >> >> I am not too familiar with other Go libs that use a custom context. One >> place we could look is the `net/http` Request, which has a `WithContext` >> method[1] that seems to expose the behavior we're looking for. That could >> be added to the statefun context package as a standalone method (e.g. >> statefun.WithContext(sCtx Context, ctx context.Context)), but would only >> work for the private implementation. I think the statefun Context type >> being an interface instead of a concrete type complicates and restricts us >> a bit here. >> >> I guess I am not fully understanding why the statefun Context needs to be >> used so far down the line. The solution that Till proposed seems to fit the >> example you gave quite well, no? >> >> func (f *MyFunc) Invoke(ctx statefun.Context, message statefun.Message) >> error { >> logger := NewLogger() >> downCtx := context.WithValue(ctx, "logger", logger) >> return SomeOtherFunc(downCtx) >> } >> >> func SomeOtherFunc(ctx context.Context) error { >> logger := ctx.Value("logger") >> return nil >> } >> >> What does "SomeOtherFunc" need with the statefun context? I think that >> would help me, at least, understand the role of the statefun context. >> >> I'm curious what you would think about an approach that kept everything >>> as-is, by default, but allowed for a separated context and runtime in the >>> Invoke method, on an opt-in basis, via an adapter? >>> >> >> I am not involved in statefun really, but IMO that seems like quite a lot >> of overhead to just pass values via the context. Perhaps we should consider >> decomposing the statefun context itself so pieces of functionality can be >> passed around more easily? >> >> Best, >> Austin >> >> >> [1]: https://pkg.go.dev/net/http#Request.WithContext >> >> >> On Tue, Feb 22, 2022 at 10:51 AM Galen Warren <ga...@cvillewarrens.com> >> wrote: >> >>> Thanks, Seth. >>> >>> I'm curious what you would think about an approach that kept everything >>> as-is, by default, but allowed for a separated context and runtime in the >>> Invoke method, on an opt-in basis, via an adapter? >>> >>> On Tue, Feb 22, 2022 at 10:28 AM Seth Wiesman <sjwies...@gmail.com> >>> wrote: >>> >>>> Hi all, >>>> >>>> I believe the discussion revolved around: >>>> >>>> 1. fewer parameters >>>> 2. better aligned with other language sdks >>>> 3. we found precedent in other libraries (apologies this was long enough >>>> ago I cannot remember which ones, I'm looking through old discussions >>>> now) >>>> >>>> I would in general champion a solution that keeps the SDKs looking >>>> similar >>>> across languages. A big part of statefun's positioning in the market is >>>> the >>>> polyglot nature and making the transition between languages as seamless >>>> as >>>> possible is very important. >>>> >>>> Seth >>>> >>>> >>>> On Tue, Feb 22, 2022 at 4:33 AM Till Rohrmann <trohrm...@apache.org> >>>> wrote: >>>> >>>> > Hi Galen, >>>> > >>>> > Thanks for explaining the problems with the current design. I think >>>> I've >>>> > already learned quite a bit wrt Go thanks to you :-) >>>> > >>>> > From what you describe it seems indeed a bit restrictive to let the >>>> > statefun.Context contain the context.Context w/o giving access to it. >>>> Maybe @Seth >>>> > Wiesman <sjwies...@gmail.com> can elaborate a bit more on the design >>>> > decisions to make sure that we have the full picture. >>>> > >>>> > As a cheap workaround you could create a context.Context object by >>>> calling >>>> > >>>> https://github.com/knative/pkg/blob/d48172451966/logging/logger.go#L45 >>>> on >>>> > the statefun.Context and then pass this Context instance to the >>>> downstream >>>> > function. But I agree that this is not the perfect solution. >>>> > >>>> > How do other libraries handle this situation if they offer a custom >>>> > Context type? Maybe @Austin Cawley-Edwards <austin.caw...@gmail.com> >>>> you >>>> > have an opinion on the matter. >>>> > >>>> > Cheers, >>>> > Till >>>> > >>>> > On Mon, Feb 21, 2022 at 7:42 PM Galen Warren <ga...@cvillewarrens.com >>>> > >>>> > wrote: >>>> > >>>> >> So, upon further fiddling, I think it would be possible to keep full >>>> >> backward compatibility and add the option for someone to use an >>>> Invoke >>>> >> method with a separate context.Context and statefun.Runtime, via an >>>> >> adapter, if direct manipulation of the context.Context is needed. So, >>>> >> basically, the idea would be to let the user choose the form of the >>>> Invoke >>>> >> method, with the default behavior remaining the same as now. >>>> >> >>>> >> This would require: >>>> >> >>>> >> - Recreating the Runtime interface (all methods currently defined >>>> on >>>> >> Context except not embedding context.Context) and embedding it in >>>> the >>>> >> statefun.Context interface, so that statefun.Context remains >>>> >> effectively >>>> >> unchanged >>>> >> - Add StatefulFunctionV2 and StatefunFunctionV2Pointer to support >>>> the >>>> >> new signature with separate context and runtime >>>> >> - Add StatefulFunctionV2Adapter to wrap a StatefulFunctionV2 and >>>> expose >>>> >> it as a StatefulFunction. The statefun.Context would get split >>>> into a >>>> >> context.Context and a statefun.Runtime here in order to call the >>>> new >>>> >> signature. >>>> >> >>>> >> Thoughts? I'd be happy to take a crack at it. >>>> >> >>>> >> >>>> >> On Mon, Feb 21, 2022 at 12:06 PM Galen Warren < >>>> ga...@cvillewarrens.com> >>>> >> wrote: >>>> >> >>>> >> > Was the reason to combine them the desire to have two parameters >>>> vs. >>>> >> > three, or was there another motivation? >>>> >> > >>>> >> > On Mon, Feb 21, 2022 at 12:02 PM Seth Wiesman <sjwies...@gmail.com >>>> > >>>> >> wrote: >>>> >> > >>>> >> >> FWIW I received a lot of early feedback explicitly asking me to >>>> couple >>>> >> the >>>> >> >> statefun specific operations with the Context (why the runtime >>>> type >>>> >> went >>>> >> >> away). >>>> >> >> >>>> >> >> Seth >>>> >> >> >>>> >> >> On Mon, Feb 21, 2022 at 10:32 AM Galen Warren < >>>> ga...@cvillewarrens.com >>>> >> > >>>> >> >> wrote: >>>> >> >> >>>> >> >> > Thanks for looking into this! >>>> >> >> > >>>> >> >> > The issue I think we'd run into with your proposal is that, >>>> often, >>>> >> >> > libraries use non-exported types for context keys. Here is an >>>> example >>>> >> >> > < >>>> >> >>>> https://github.com/knative/pkg/blob/d48172451966/logging/logger.go#L45 >>>> >> >> >; >>>> >> >> > in this case, the non-exported loggerKey{} is used as the key, >>>> inside >>>> >> >> the >>>> >> >> > exported WithLogger function. The key that would have to be >>>> supplied >>>> >> to >>>> >> >> the >>>> >> >> > proposed Value and WithValue functions would not be accessible >>>> in >>>> >> this >>>> >> >> > case. >>>> >> >> > >>>> >> >> > Honestly, if *everything *were on the table -- and understand >>>> it very >>>> >> >> well >>>> >> >> > might not be -- I'd suggest decoupling the Golang >>>> context.Context and >>>> >> >> the >>>> >> >> > statefun Context, i.e. have two separate parameters to >>>> >> >> > StatefulFunction.Invoke representing Golang context and statefun >>>> >> >> > operations. This is actually how things were in an earlier >>>> version of >>>> >> >> the >>>> >> >> > Golang SDK; the first parameter to Invoke was the plain-vanilla >>>> >> >> > context.Context and a separate parameter provided the statefun >>>> >> >> "runtime". >>>> >> >> > So maybe something like this: >>>> >> >> > >>>> >> >> > > >>>> >> >> > > type StatefulFunction interface { >>>> >> >> > > Invoke(ctx context.Context, runtime Runtime, message Message) >>>> error >>>> >> >> > > } >>>> >> >> > >>>> >> >> > >>>> >> >> > ... instead of the current: >>>> >> >> > >>>> >> >> > type StatefulFunction interface { >>>> >> >> > > Invoke(ctx Context, message Message) error >>>> >> >> > > } >>>> >> >> > >>>> >> >> > >>>> >> >> > ... where Runtime would be everything currently in >>>> statefun.Context, >>>> >> >> except >>>> >> >> > the context.Context part. This would allow context.Context to be >>>> >> >> > manipulated and passed around normally. >>>> >> >> > >>>> >> >> > I think this could potentially be done in a backward-compatible >>>> way, >>>> >> >> with a >>>> >> >> > new set of types and methods, e.g. StatefulFunctionV2, >>>> >> >> > StatefufFunctionSpecV2, StatefulFunctions.WithSpecV2, etc. Or it >>>> >> could >>>> >> >> be >>>> >> >> > done in an almost backward-compatible way, by changing the >>>> existing >>>> >> >> > StatefulFunction, StatefulFunctionSpec, >>>> StatefulFunctions.WithSpec >>>> >> and >>>> >> >> > providing an adapter for people who want to continue to use the >>>> >> >> > two-parameter version of Invoke. >>>> >> >> > >>>> >> >> > If those kinds of changes are a non-starter, then IMO the next >>>> best >>>> >> >> option >>>> >> >> > would be adding something like: >>>> >> >> > >>>> >> >> > PrepareContext func(ctx statefun.Context) context.Context >>>> >> >> > >>>> >> >> > >>>> >> >> > ... to StatefulFunctionSpec to allow a one-time customization >>>> of the >>>> >> >> > underlying context at the beginning of a stateful function >>>> >> invocation. >>>> >> >> That >>>> >> >> > would cover a lot of use cases. >>>> >> >> > >>>> >> >> > >>>> >> >> > On Mon, Feb 21, 2022 at 3:06 AM Till Rohrmann < >>>> trohrm...@apache.org> >>>> >> >> > wrote: >>>> >> >> > >>>> >> >> > > Thanks a lot for clarifying the problem. I think I now >>>> understand >>>> >> the >>>> >> >> > > problem. As you've probably figured out, I have no clue about >>>> Go >>>> >> and >>>> >> >> > > its usage of the Context type. >>>> >> >> > > >>>> >> >> > > After looking into it a bit I was wondering whether we can't >>>> >> follow a >>>> >> >> > > similar route as it is done for the Context type. By adding >>>> >> something >>>> >> >> > like >>>> >> >> > > >>>> >> >> > > type valueCtx struct { >>>> >> >> > > Context >>>> >> >> > > key, val interface{} >>>> >> >> > > } >>>> >> >> > > >>>> >> >> > > func (c *valueCtx) Value(key interface{}) interface{} { >>>> >> >> > > if c.key == key { >>>> >> >> > > return c.val >>>> >> >> > > } >>>> >> >> > > return c.Context.Value(key) >>>> >> >> > > } >>>> >> >> > > >>>> >> >> > > func WithValue(parent Context, key, val interface{}) Context { >>>> >> >> > > if parent == nil { >>>> >> >> > > panic("cannot create context from nil parent") >>>> >> >> > > } >>>> >> >> > > if key == nil { >>>> >> >> > > panic("nil key") >>>> >> >> > > } >>>> >> >> > > return &valueCtx{parent, key, val} >>>> >> >> > > } >>>> >> >> > > >>>> >> >> > > to the statefun/context.go we would allow to extend a Statefun >>>> >> context >>>> >> >> > with >>>> >> >> > > values w/o changing the underlying instance. If >>>> statefun.Context is >>>> >> >> not >>>> >> >> > > needed, then there is already the option to unwrap the >>>> >> context.Context >>>> >> >> > and >>>> >> >> > > to extend it with values and then pass on this instance. But >>>> maybe >>>> >> >> this >>>> >> >> > is >>>> >> >> > > no idiomatic Go. Let me know what you think. >>>> >> >> > > >>>> >> >> > > Cheers, >>>> >> >> > > Till >>>> >> >> > > >>>> >> >> > > On Fri, Feb 18, 2022 at 7:01 PM Galen Warren < >>>> >> ga...@cvillewarrens.com >>>> >> >> > >>>> >> >> > > wrote: >>>> >> >> > > >>>> >> >> > > > Hmm ... a downside to my proposal is that Go contexts are >>>> >> supposed >>>> >> >> to >>>> >> >> > be >>>> >> >> > > > immutable, i.e. when adding a custom value to a context, a >>>> new >>>> >> >> context >>>> >> >> > is >>>> >> >> > > > created with the new value and the old context isn't >>>> changed. >>>> >> >> Changing >>>> >> >> > > the >>>> >> >> > > > context.Context associated with the statefun.Context sort >>>> of goes >>>> >> >> > against >>>> >> >> > > > the spirit of that, i.e. a consumer of statefun.Context >>>> could see >>>> >> >> > custom >>>> >> >> > > > values change unexpectedly if another consumer of the same >>>> >> >> > > statefun.Context >>>> >> >> > > > modified the underlying context.Context. >>>> >> >> > > > >>>> >> >> > > > To avoid that, I think we'd be back to having some >>>> mechanism to >>>> >> >> > customize >>>> >> >> > > > the underlying context.Context once, when the >>>> statefun.Context is >>>> >> >> > created >>>> >> >> > > > at the beginning of a stateful function invocation. Adding a >>>> >> field >>>> >> >> > like: >>>> >> >> > > > >>>> >> >> > > > PrepareContext func(ctx statefun.Context) context.Context >>>> >> >> > > > >>>> >> >> > > > ... to the StatefulFunctionSpec struct could accomplish >>>> that, >>>> >> i.e. >>>> >> >> if >>>> >> >> > > > PrepareContext were supplied, the context could be >>>> customized >>>> >> once >>>> >> >> at >>>> >> >> > the >>>> >> >> > > > start of a function invocation and then left immutable >>>> after that >>>> >> >> > point. >>>> >> >> > > > >>>> >> >> > > > (Using statefun.Context as the input is deliberate here, in >>>> >> order to >>>> >> >> > > allow >>>> >> >> > > > the context.Context to be populated using values from the >>>> >> >> > > statefun.Context, >>>> >> >> > > > for example the function id). >>>> >> >> > > > >>>> >> >> > > > >>>> >> >> > > > >>>> >> >> > > > >>>> >> >> > > > >>>> >> >> > > > >>>> >> >> > > > On Fri, Feb 18, 2022 at 11:34 AM Galen Warren < >>>> >> >> ga...@cvillewarrens.com >>>> >> >> > > >>>> >> >> > > > wrote: >>>> >> >> > > > >>>> >> >> > > > > An example of passing it around would be: >>>> >> >> > > > > >>>> >> >> > > > > func (f *MyFunc) Invoke(ctx statefun.Context, message >>>> >> >> > statefun.Message) >>>> >> >> > > > > error { >>>> >> >> > > > > >>>> >> >> > > > > logger := NewLogger() >>>> >> >> > > > > ctx.SetContext(ctxzap.ToContext(ctx, logger)) >>>> >> >> > > > > >>>> >> >> > > > > return SomeOtherFunc(ctx) >>>> >> >> > > > > } >>>> >> >> > > > > >>>> >> >> > > > > func SomeOtherFunc(ctx context.Context) error { >>>> >> >> > > > > >>>> >> >> > > > > logger := ctxzap.Extract(ctx) >>>> >> >> > > > > logger.Info(...) >>>> >> >> > > > > >>>> >> >> > > > > return nil >>>> >> >> > > > > } >>>> >> >> > > > > >>>> >> >> > > > > This would also work with further nested calls, so long >>>> as the >>>> >> >> > context >>>> >> >> > > is >>>> >> >> > > > > passed to them. >>>> >> >> > > > > >>>> >> >> > > > > On Fri, Feb 18, 2022 at 11:23 AM Galen Warren < >>>> >> >> > ga...@cvillewarrens.com >>>> >> >> > > > >>>> >> >> > > > > wrote: >>>> >> >> > > > > >>>> >> >> > > > >> Ha, our emails keep passing. >>>> >> >> > > > >> >>>> >> >> > > > >> I've been playing around with options locally, and the >>>> >> SetContext >>>> >> >> > > option >>>> >> >> > > > >> seems to be the most flexible (and non-breaking), imo. >>>> >> >> > > > >> >>>> >> >> > > > >> The implementation would be trivial, just add: >>>> >> >> > > > >> >>>> >> >> > > > >> SetContext(ctx context.Context) >>>> >> >> > > > >> >>>> >> >> > > > >> ... to the statefun.Context interface, which is >>>> implemented >>>> >> as: >>>> >> >> > > > >> >>>> >> >> > > > >> func (s *statefunContext) SetContext(ctx >>>> context.Context) { >>>> >> >> > > > >> s.Context = ctx >>>> >> >> > > > >> } >>>> >> >> > > > >> >>>> >> >> > > > >> >>>> >> >> > > > >> >>>> >> >> > > > >> >>>> >> >> > > > >> On Fri, Feb 18, 2022 at 11:18 AM Austin Cawley-Edwards < >>>> >> >> > > > >> austin.caw...@gmail.com> wrote: >>>> >> >> > > > >> >>>> >> >> > > > >>> It would be helpful to have a small example though, if >>>> you >>>> >> have >>>> >> >> on >>>> >> >> > > > Galen, >>>> >> >> > > > >>> to see how you're passing it around. >>>> >> >> > > > >>> >>>> >> >> > > > >>> On Fri, Feb 18, 2022 at 11:10 AM Austin Cawley-Edwards < >>>> >> >> > > > >>> austin.caw...@gmail.com> wrote: >>>> >> >> > > > >>> >>>> >> >> > > > >>> > Looking through the statefun Context interface, it >>>> indeed >>>> >> >> doesn't >>>> >> >> > > > give >>>> >> >> > > > >>> > access to the underlying context.Context and the only >>>> >> >> > > implementation >>>> >> >> > > > is >>>> >> >> > > > >>> > package-private [1]. I don't think there would be a >>>> way to >>>> >> >> update >>>> >> >> > > the >>>> >> >> > > > >>> > statfun.Context interface without introducing breaking >>>> >> >> changes, >>>> >> >> > but >>>> >> >> > > > if >>>> >> >> > > > >>> we >>>> >> >> > > > >>> > were to make that implementation public, that might >>>> be a >>>> >> >> stopgap >>>> >> >> > > > >>> solution. >>>> >> >> > > > >>> > e.g., >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > ``` >>>> >> >> > > > >>> > type StatefunContext struct { >>>> >> >> > > > >>> > // expose embedded context >>>> >> >> > > > >>> > context.Context >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > // make the mutext private >>>> >> >> > > > >>> > mu sync.Mutex >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > // keep internals private >>>> >> >> > > > >>> > self Address >>>> >> >> > > > >>> > caller *Address >>>> >> >> > > > >>> > storage *storage >>>> >> >> > > > >>> > response *protocol.FromFunction_InvocationResponse >>>> >> >> > > > >>> > } >>>> >> >> > > > >>> > ``` >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > You could then do a type assertion in the handlers >>>> for this >>>> >> >> type >>>> >> >> > of >>>> >> >> > > > >>> > context, and modify the context on it directly. It >>>> would >>>> >> be a >>>> >> >> bit >>>> >> >> > > > >>> ugly, but >>>> >> >> > > > >>> > may work. >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > ``` >>>> >> >> > > > >>> > func (s aFunc) Invoke(ctx Context, message Message) >>>> error { >>>> >> >> > > > >>> > if sCtx, ok := ctx.(*statefun.StatefunContext); ok { >>>> >> >> > > > >>> > sCtx.Context = context.WithValue(sCtx.Context, >>>> >> "logger", >>>> >> >> > > aLogger) >>>> >> >> > > > >>> > } >>>> >> >> > > > >>> > // ... >>>> >> >> > > > >>> > } >>>> >> >> > > > >>> > ``` >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > Let me know what you all think, >>>> >> >> > > > >>> > Austin >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > [1]: >>>> >> >> > > > >>> > >>>> >> >> > > > >>> >>>> >> >> > > > >>>> >> >> > > >>>> >> >> > >>>> >> >> >>>> >> >>>> https://github.com/apache/flink-statefun/blob/1dfe226d85fea05a46c8ffa688175b4c0f2d4900/statefun-sdk-go/v3/pkg/statefun/context.go#L66-L73 >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > On Fri, Feb 18, 2022 at 11:03 AM Galen Warren < >>>> >> >> > > > ga...@cvillewarrens.com >>>> >> >> > > > >>> > >>>> >> >> > > > >>> > wrote: >>>> >> >> > > > >>> > >>>> >> >> > > > >>> >> Sorry Austin, I didn't see your response before I >>>> replied. >>>> >> >> Yes, >>>> >> >> > > > we're >>>> >> >> > > > >>> >> saying the same thing. >>>> >> >> > > > >>> >> >>>> >> >> > > > >>> >> On Fri, Feb 18, 2022 at 10:56 AM Austin >>>> Cawley-Edwards < >>>> >> >> > > > >>> >> austin.caw...@gmail.com> wrote: >>>> >> >> > > > >>> >> >>>> >> >> > > > >>> >> > Hey all, jumping in. This makes sense to me – for >>>> >> instance >>>> >> >> to >>>> >> >> > > > >>> attach a >>>> >> >> > > > >>> >> > logger with some common metadata, e.g trace ID for >>>> the >>>> >> >> > request? >>>> >> >> > > > >>> This is >>>> >> >> > > > >>> >> > common in go to add arbitrary items without >>>> updating the >>>> >> >> > method >>>> >> >> > > > >>> >> signatures, >>>> >> >> > > > >>> >> > similar to thread local storage in Java. >>>> >> >> > > > >>> >> > >>>> >> >> > > > >>> >> > On Fri, Feb 18, 2022 at 10:53 AM Till Rohrmann < >>>> >> >> > > > >>> trohrm...@apache.org> >>>> >> >> > > > >>> >> > wrote: >>>> >> >> > > > >>> >> > >>>> >> >> > > > >>> >> > > Thanks for the clarification Galen. If you call >>>> the >>>> >> >> other Go >>>> >> >> > > > >>> >> functions, >>>> >> >> > > > >>> >> > > then you could also pass the other values as >>>> separate >>>> >> >> > > arguments >>>> >> >> > > > to >>>> >> >> > > > >>> >> these >>>> >> >> > > > >>> >> > > functions, can't you? >>>> >> >> > > > >>> >> > > >>>> >> >> > > > >>> >> > > Cheers, >>>> >> >> > > > >>> >> > > Till >>>> >> >> > > > >>> >> > > >>>> >> >> > > > >>> >> > > On Fri, Feb 18, 2022 at 3:31 PM Galen Warren < >>>> >> >> > > > >>> ga...@cvillewarrens.com >>>> >> >> > > > >>> >> > >>>> >> >> > > > >>> >> > > wrote: >>>> >> >> > > > >>> >> > > >>>> >> >> > > > >>> >> > > > The former. >>>> >> >> > > > >>> >> > > > >>>> >> >> > > > >>> >> > > > I think there's potential for confusion here >>>> because >>>> >> >> we're >>>> >> >> > > > >>> using the >>>> >> >> > > > >>> >> > > > word *function >>>> >> >> > > > >>> >> > > > *in a couple of senses. One sense is a >>>> *stateful >>>> >> >> > function*; >>>> >> >> > > > >>> another >>>> >> >> > > > >>> >> > sense >>>> >> >> > > > >>> >> > > > is a *Go function*. >>>> >> >> > > > >>> >> > > > >>>> >> >> > > > >>> >> > > > What I'm looking to do is to put values in the >>>> >> Context >>>> >> >> so >>>> >> >> > > that >>>> >> >> > > > >>> >> > downstream >>>> >> >> > > > >>> >> > > > Go functions that receive the context can >>>> access >>>> >> those >>>> >> >> > > values. >>>> >> >> > > > >>> Those >>>> >> >> > > > >>> >> > > > downstream Go functions would be called during >>>> one >>>> >> >> > > invocation >>>> >> >> > > > >>> of the >>>> >> >> > > > >>> >> > > > stateful function. >>>> >> >> > > > >>> >> > > > >>>> >> >> > > > >>> >> > > > On Fri, Feb 18, 2022 at 6:48 AM Till Rohrmann < >>>> >> >> > > > >>> trohrm...@apache.org >>>> >> >> > > > >>> >> > >>>> >> >> > > > >>> >> > > > wrote: >>>> >> >> > > > >>> >> > > > >>>> >> >> > > > >>> >> > > > > Hi Galen, >>>> >> >> > > > >>> >> > > > > >>>> >> >> > > > >>> >> > > > > Am I understanding it correctly, that you >>>> would >>>> >> like >>>> >> >> to >>>> >> >> > > set >>>> >> >> > > > >>> some >>>> >> >> > > > >>> >> > values >>>> >> >> > > > >>> >> > > > in >>>> >> >> > > > >>> >> > > > > the Context of function A that is then >>>> accessible >>>> >> in >>>> >> >> a >>>> >> >> > > > >>> downstream >>>> >> >> > > > >>> >> > call >>>> >> >> > > > >>> >> > > of >>>> >> >> > > > >>> >> > > > > function B? Or would you like to set a value >>>> that >>>> >> is >>>> >> >> > > > >>> accessible >>>> >> >> > > > >>> >> once >>>> >> >> > > > >>> >> > > > > function A is called again (w/ or w/o the >>>> same >>>> >> id)? >>>> >> >> > > > >>> >> > > > > >>>> >> >> > > > >>> >> > > > > Cheers, >>>> >> >> > > > >>> >> > > > > Till >>>> >> >> > > > >>> >> > > > > >>>> >> >> > > > >>> >> > > > > On Thu, Feb 17, 2022 at 10:59 PM Galen >>>> Warren < >>>> >> >> > > > >>> >> > ga...@cvillewarrens.com >>>> >> >> > > > >>> >> > > > >>>> >> >> > > > >>> >> > > > > wrote: >>>> >> >> > > > >>> >> > > > > >>>> >> >> > > > >>> >> > > > > > Also, a potentially simpler way to support >>>> this >>>> >> >> would >>>> >> >> > be >>>> >> >> > > > to >>>> >> >> > > > >>> add >>>> >> >> > > > >>> >> a >>>> >> >> > > > >>> >> > > > > > SetContext method to the statefun.Context >>>> >> >> interface, >>>> >> >> > and >>>> >> >> > > > >>> have it >>>> >> >> > > > >>> >> > > assign >>>> >> >> > > > >>> >> > > > > the >>>> >> >> > > > >>> >> > > > > > wrapped context. This would not require >>>> changes >>>> >> to >>>> >> >> the >>>> >> >> > > > >>> function >>>> >> >> > > > >>> >> > spec, >>>> >> >> > > > >>> >> > > > or >>>> >> >> > > > >>> >> > > > > > anything else, and would be more flexible. >>>> >> >> > > > >>> >> > > > > > >>>> >> >> > > > >>> >> > > > > > On Thu, Feb 17, 2022 at 1:05 PM Galen >>>> Warren < >>>> >> >> > > > >>> >> > > ga...@cvillewarrens.com> >>>> >> >> > > > >>> >> > > > > > wrote: >>>> >> >> > > > >>> >> > > > > > >>>> >> >> > > > >>> >> > > > > > > Thanks for the quick reply! >>>> >> >> > > > >>> >> > > > > > > >>>> >> >> > > > >>> >> > > > > > > What I'm trying to do is put some things >>>> into >>>> >> the >>>> >> >> > > > context >>>> >> >> > > > >>> so >>>> >> >> > > > >>> >> that >>>> >> >> > > > >>> >> > > > > they're >>>> >> >> > > > >>> >> > > > > > > available in downstream calls, perhaps in >>>> >> methods >>>> >> >> > with >>>> >> >> > > > >>> pointer >>>> >> >> > > > >>> >> > > > > receivers >>>> >> >> > > > >>> >> > > > > > to >>>> >> >> > > > >>> >> > > > > > > the function struct (MyFunc) but also >>>> perhaps >>>> >> in >>>> >> >> > > methods >>>> >> >> > > > >>> that >>>> >> >> > > > >>> >> are >>>> >> >> > > > >>> >> > > > > further >>>> >> >> > > > >>> >> > > > > > > downstream that don't have access to >>>> MyFunc. >>>> >> If >>>> >> >> I'm >>>> >> >> > > > >>> >> understanding >>>> >> >> > > > >>> >> > > > > > > correctly, your proposal would work for >>>> the >>>> >> >> former >>>> >> >> > but >>>> >> >> > > > >>> not the >>>> >> >> > > > >>> >> > > > latter. >>>> >> >> > > > >>> >> > > > > > > >>>> >> >> > > > >>> >> > > > > > > An example would be to put a configured >>>> Logger >>>> >> >> into >>>> >> >> > > the >>>> >> >> > > > >>> >> context >>>> >> >> > > > >>> >> > > via a >>>> >> >> > > > >>> >> > > > > > > WithLogger method (logging package - >>>> >> >> > > > >>> knative.dev/pkg/logging >>>> >> >> > > > >>> >> - >>>> >> >> > > > >>> >> > > > > > pkg.go.dev >>>> >> >> > > > >>> >> > > > > > > < >>>> >> >> > > https://pkg.go.dev/knative.dev/pkg/logging#WithLogger >>>> >> >> > > > >) >>>> >> >> > > > >>> and >>>> >> >> > > > >>> >> > then >>>> >> >> > > > >>> >> > > > pull >>>> >> >> > > > >>> >> > > > > > it >>>> >> >> > > > >>> >> > > > > > > out downstream via FromContext (logging >>>> >> package - >>>> >> >> > > > >>> >> > > > > > knative.dev/pkg/logging >>>> >> >> > > > >>> >> > > > > > > - pkg.go.dev < >>>> >> >> > > > >>> >> > > >>>> >> https://pkg.go.dev/knative.dev/pkg/logging#FromContext >>>> >> >> > > > >>> >> > > > > >). >>>> >> >> > > > >>> >> > > > > > > >>>> >> >> > > > >>> >> > > > > > > >>>> >> >> > > > >>> >> > > > > > > >>>> >> >> > > > >>> >> > > > > > > >>>> >> >> > > > >>> >> > > > > > > On Wed, Feb 16, 2022 at 5:50 PM Seth >>>> Wiesman < >>>> >> >> > > > >>> >> > sjwies...@gmail.com> >>>> >> >> > > > >>> >> > > > > > wrote: >>>> >> >> > > > >>> >> > > > > > > >>>> >> >> > > > >>> >> > > > > > >> Hi Galen, >>>> >> >> > > > >>> >> > > > > > >> >>>> >> >> > > > >>> >> > > > > > >> No, that is not currently supported, the >>>> >> current >>>> >> >> > > > >>> idiomatic >>>> >> >> > > > >>> >> way >>>> >> >> > > > >>> >> > > would >>>> >> >> > > > >>> >> > > > > be >>>> >> >> > > > >>> >> > > > > > to >>>> >> >> > > > >>> >> > > > > > >> pass those values to the struct >>>> implementing >>>> >> the >>>> >> >> > > > Statefun >>>> >> >> > > > >>> >> > > interface. >>>> >> >> > > > >>> >> > > > > > >> >>>> >> >> > > > >>> >> > > > > > >> >>>> >> >> > > > >>> >> > > > > > >> type MyFunc struct { someRuntimeInfo >>>> string } >>>> >> >> func >>>> >> >> > (m >>>> >> >> > > > >>> >> *MyFunc) >>>> >> >> > > > >>> >> > > > > > Invoke(ctx >>>> >> >> > > > >>> >> > > > > > >> statefun.Context, message >>>> statefun.Message) >>>> >> >> error >>>> >> >> > { } >>>> >> >> > > > >>> func >>>> >> >> > > > >>> >> > main() >>>> >> >> > > > >>> >> > > { >>>> >> >> > > > >>> >> > > > > > >> builder >>>> >> >> > > > >>> >> > > > > > >> := statefun.StatefulFunctionsBuilder() >>>> >> >> > > > >>> >> > > > > > >> f := MyFunc { someRuntimeInfo: >>>> >> >> "runtime-provided" } >>>> >> >> > > > >>> >> > > builder.WithSpec >>>> >> >> > > > >>> >> > > > > > >> (statefun.StatefulFunctionSpec{ >>>> FunctionType: >>>> >> >> > > > >>> >> > > statefun.TypeNameFrom( >>>> >> >> > > > >>> >> > > > > > >> "example/my-func"), Function: f }) >>>> >> >> > > > >>> >> > > > > > >> http.Handle("/statefun", >>>> builder.AsHandler()) >>>> >> >> > > > >>> >> > > > > > >> _ = http.ListenAndServe(":8000", nil) } >>>> >> >> > > > >>> >> > > > > > >> >>>> >> >> > > > >>> >> > > > > > >> Would this work for you? Or what is the >>>> >> context >>>> >> >> > (pun >>>> >> >> > > > >>> >> intended) >>>> >> >> > > > >>> >> > you >>>> >> >> > > > >>> >> > > > are >>>> >> >> > > > >>> >> > > > > > >> looking for? >>>> >> >> > > > >>> >> > > > > > >> >>>> >> >> > > > >>> >> > > > > > >> Seth >>>> >> >> > > > >>> >> > > > > > >> >>>> >> >> > > > >>> >> > > > > > >> On Wed, Feb 16, 2022 at 4:35 PM Galen >>>> Warren >>>> >> < >>>> >> >> > > > >>> >> > > > ga...@cvillewarrens.com >>>> >> >> > > > >>> >> > > > > > >>>> >> >> > > > >>> >> > > > > > >> wrote: >>>> >> >> > > > >>> >> > > > > > >> >>>> >> >> > > > >>> >> > > > > > >> > When stateful functions are invoked, >>>> they >>>> >> are >>>> >> >> > > passed >>>> >> >> > > > an >>>> >> >> > > > >>> >> > instance >>>> >> >> > > > >>> >> > > > of >>>> >> >> > > > >>> >> > > > > > >> > statefun.Context, which wraps the >>>> >> >> context.Context >>>> >> >> > > > >>> received >>>> >> >> > > > >>> >> by >>>> >> >> > > > >>> >> > > the >>>> >> >> > > > >>> >> > > > > HTTP >>>> >> >> > > > >>> >> > > > > > >> > request. Is there any way to >>>> customize that >>>> >> >> > > > >>> context.Context >>>> >> >> > > > >>> >> > to, >>>> >> >> > > > >>> >> > > > say, >>>> >> >> > > > >>> >> > > > > > >> hold >>>> >> >> > > > >>> >> > > > > > >> > custom values, using ctx.WithValue()? >>>> I >>>> >> don't >>>> >> >> > see a >>>> >> >> > > > way >>>> >> >> > > > >>> >> but I >>>> >> >> > > > >>> >> > > > wanted >>>> >> >> > > > >>> >> > > > > > to >>>> >> >> > > > >>> >> > > > > > >> > ask. >>>> >> >> > > > >>> >> > > > > > >> > >>>> >> >> > > > >>> >> > > > > > >> > If not, would you be interested in a >>>> PR to >>>> >> add >>>> >> >> > this >>>> >> >> > > > >>> >> > > > functionality? A >>>> >> >> > > > >>> >> > > > > > >> simple >>>> >> >> > > > >>> >> > > > > > >> > way might be to add a property to >>>> >> >> > > > StatefulFunctionSpec, >>>> >> >> > > > >>> >> say: >>>> >> >> > > > >>> >> > > > > > >> > >>>> >> >> > > > >>> >> > > > > > >> > TransformContext func(ctx >>>> context.Context) >>>> >> >> > > > >>> context.Context >>>> >> >> > > > >>> >> > > > > > >> > >>>> >> >> > > > >>> >> > > > > > >> > ... that, if supplied, would be >>>> called to >>>> >> >> create >>>> >> >> > a >>>> >> >> > > > >>> >> customized >>>> >> >> > > > >>> >> > > > > context >>>> >> >> > > > >>> >> > > > > > >> that >>>> >> >> > > > >>> >> > > > > > >> > would be used downstream? >>>> >> >> > > > >>> >> > > > > > >> > >>>> >> >> > > > >>> >> > > > > > >> > Thanks. >>>> >> >> > > > >>> >> > > > > > >> > >>>> >> >> > > > >>> >> > > > > > >> >>>> >> >> > > > >>> >> > > > > > > >>>> >> >> > > > >>> >> > > > > > >>>> >> >> > > > >>> >> > > > > >>>> >> >> > > > >>> >> > > > >>>> >> >> > > > >>> >> > > >>>> >> >> > > > >>> >> > >>>> >> >> > > > >>> >> >>>> >> >> > > > >>> > >>>> >> >> > > > >>> >>>> >> >> > > > >> >>>> >> >> > > > >>>> >> >> > > >>>> >> >> > >>>> >> >> >>>> >> > >>>> >> >>>> > >>>> >>>