Giter Site home page Giter Site logo

RFC: fx.Context as a struct about fx HOT 12 CLOSED

abhinav avatar abhinav commented on August 19, 2024 3
RFC: fx.Context as a struct

from fx.

Comments (12)

abhinav avatar abhinav commented on August 19, 2024 1

ctx.(fx.Context) won't work if anything between the UberFx middleware and
WrapUnary calls context.WithValue on the context because the returned ctx
will not have the added fx.Context functions anymore.

from fx.

prashantv avatar prashantv commented on August 19, 2024

There may be performance implications to using a struct, since we'll be passing the struct by value, and when a by-value object is converted to an interface, it requires an allocation. Since the fx.Context will be passed to methods that expect a context.Context interface, it's possible that each of these will require an extra allocation to do the interface conversion.

We should ensure there's no performance hit if we want to do this.

from fx.

ascandella avatar ascandella commented on August 19, 2024

cc @anuptalwalkar who is doing the implementation

from fx.

ascandella avatar ascandella commented on August 19, 2024

And yes, the interface conversion was the primary motivation for us using an interface in he first place.

from fx.

abhinav avatar abhinav commented on August 19, 2024

If this affects perf negatively, an interface can still be used to get
context.Context compatibility provided that UberFx maintains control of all
implementations by adding a private method to the interface and providing a
public function to upgrade a context.Context back to an fx.Context.

package fx

type Context interface {
    context.Context
    
    // unexported function to ensure only this package implements this
    // interface.
    fx()
    
    // ...
}

func Upgrade(context.Context) Context {  // Better name TBD
    return &context{...}
}

func NewContext(context.Context, Host) Context {
    // ...
}

type context struct {
    // ..
}

func (c *context) fx() {}

func (c *context) Logger() Logger {
    return GetLogger(c.Context)
}

This gets rid of the fx.Context -> context.Context alloc.

from fx.

ascandella avatar ascandella commented on August 19, 2024

from fx.

prashantv avatar prashantv commented on August 19, 2024

Private method on the interface is a good idea. I'd avoid adding the Upgrade -- my understanding is that this shouldn't be needed, and the uberfx team actively wants to avoid wrapping.

from fx.

anuptalwalkar avatar anuptalwalkar commented on August 19, 2024

I like the private method idea to keep the implementation restricted.
Is there a performance impact on doing fxCtx := ctx.(fx.Context) ?

from fx.

abhinav avatar abhinav commented on August 19, 2024

@anuptalwalkar ctx.(fx.Context) will not work if context.WithValue was
used on an fx.Context.

fxctx := fx.NewContext(...)
ctx := context.WithValue(fxctx, ...)

fxctx2 := ctx.(fx.Context)  // this will panic

The two solutions recommended here would solve that.

@prashantv The upgrade function is needed to solve the problem mentioned
above. On second thought, it doesn't have to be public, but we definitely need
it.

Imagine that an UberFx InboundMiddleware adds UberFx information to incoming
contexts:

func (m *ctxMiddleware) Handle(
    ctx context.Context, ..., h transport.UnaryHandler,
) error {
    fxctx := fx.NewContext(ctx, m.Host)
    return h.Handle(fxctx, ...)
}

We get this context as a context.Context at the encoding layer. We need to
convert this back to an fx.Context to call the user handler. This would be
done with UberFx's Thrift function wrapper.

func WrapUnary(h fxthrift.UnaryHandlerFunc) yarpcthrift.UnaryHandler {
    return func(ctx context.Context, ...) error {
       fxctx := upgrade(ctx)
       return h(fxctx, ...)
    }
}

from fx.

anuptalwalkar avatar anuptalwalkar commented on August 19, 2024

I am following the same approach in the refactoring. Well, ctx.(fx.Context) works in WrapUnary since it is injected in the inboundMiddleware (unless we write a middleware to do WithValue in between the calls), but in this scenario upgrade works just as well. We definitely don't want to do unnecessary wrapping.

from fx.

ascandella avatar ascandella commented on August 19, 2024

from fx.

anuptalwalkar avatar anuptalwalkar commented on August 19, 2024

Added benchmarks for Context conversion - #131

from fx.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.