I agree with you Galen, adding a default implementation would not be so natural here. We could eventually change this from being an interface to just a struct (like http.Request) if there is no use case for custom implementations.
Thanks for the nice discussion here + contribution :) Austin On Wed, Feb 23, 2022 at 11:09 AM Galen Warren <ga...@cvillewarrens.com> wrote: > Thanks, Till. > > >> Is it possible in Go to provide a default implementation for a method? >> Maybe that way the introduction of the new method would not be breaking. >> > > I can't think of a way to do this that would be seamless to someone who > had chosen to create a custom struct implementing statefun.Context. We > could create a struct -- say, statefun.ContextDefaultBehavior -- that an > implementor could embed in such a custom struct and which would provide an > implementation of WithContext, but that embedding would have to be added to > the custom struct (i.e. it wouldn't prevent the initial compile-time > breakage), and there would be no way to provide an implementation that > would work in the general case. I'm not sure that would be any better than > just requiring the implementor to add a WithContext method. > > Austin, please chime in if you have a different idea. > > I'll proceed for now with the intent of adding the method to > statefun.Context. If we decide that a top-level function is a better > approach, that would be an easy switch to make. > > JIRA created: [FLINK-26340] Add ability in Golang SDK to create new > statefun.Context from existing one, but with a new underlying > context.Context - ASF JIRA (apache.org) > <https://issues.apache.org/jira/browse/FLINK-26340> > > I have the code basically done locally, so, barring objection, I'll add a > PR soon. > > > > > > > On Wed, Feb 23, 2022 at 3:41 AM Till Rohrmann <trohrm...@apache.org> > wrote: > >> Thanks a lot for the discussion Austin and Galen. I think it would be fine >> to break the API at this point in time. Moreover, I don't assume that many >> people have their own statefun.Context implementations. Is it possible in >> Go to provide a default implementation for a method? Maybe that way the >> introduction of the new method would not be breaking. >> >> Galen, do you want to open a JIRA issue for this proposal? >> >> Cheers, >> Till >> >> On Wed, Feb 23, 2022 at 12:50 AM Galen Warren <ga...@cvillewarrens.com> >> wrote: >> >> > Yeah, good point. I wasn't considering that someone else might be >> > implementing that interface. Practically, I think that's pretty >> unlikely, >> > but good question. >> > >> > >> > >> > On Tue, Feb 22, 2022 at 6:36 PM Austin Cawley-Edwards < >> > austin.caw...@gmail.com> wrote: >> > >> > > I think the only complication with adding `WithContext` to the >> interface >> > > is that it makes it breaking :/ If it were the concrete >> implementation, >> > > we'd have more flexibility. I'm not sure what guarantees are on those >> > > interfaces though – @sjwies...@gmail.com, wdyt? >> > > >> > > On Tue, Feb 22, 2022 at 4:19 PM Galen Warren <ga...@cvillewarrens.com >> > >> > > wrote: >> > > >> > >> I think I would choose the WithContext method at this point, assuming >> > >> that the implementation keeps any instance of the stateful context >> > >> immutable (which should be doable). It's the simplest option IMO, >> > simpler >> > >> than an adapter approach. Thanks for the suggestion. >> > >> >> > >> My slight preference would be to add 'WithContext' as a method to >> > >> statefun.Context (similar to your Request.WithContext example >> > >> <https://pkg.go.dev/net/http#Request.WithContext>), as opposed to a >> > >> top-level function, i.e. statefun.WithContext, but either one could >> > work. >> > >> >> > >> Would that work for you? What do the rest of you think? >> > >> >> > >> >> > >> >> > >> On Tue, Feb 22, 2022 at 3:52 PM Austin Cawley-Edwards < >> > >> austin.caw...@gmail.com> wrote: >> > >> >> > >>> 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. >> > >>>>>>> >> >> > > > >>> >> > > > > > >> > >> > >>>>>>> >> >> > > > >>> >> > > > > > >> >> > >>>>>>> >> >> > > > >>> >> > > > > > > >> > >>>>>>> >> >> > > > >>> >> > > > > > >> > >>>>>>> >> >> > > > >>> >> > > > > >> > >>>>>>> >> >> > > > >>> >> > > > >> > >>>>>>> >> >> > > > >>> >> > > >> > >>>>>>> >> >> > > > >>> >> > >> > >>>>>>> >> >> > > > >>> >> >> > >>>>>>> >> >> > > > >>> > >> > >>>>>>> >> >> > > > >>> >> > >>>>>>> >> >> > > > >> >> > >>>>>>> >> >> > > > >> > >>>>>>> >> >> > > >> > >>>>>>> >> >> > >> > >>>>>>> >> >> >> > >>>>>>> >> > >> > >>>>>>> >> >> > >>>>>>> > >> > >>>>>>> >> > >>>>>> >> > >> >