Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: inferred func names are ambiguous, cause misbehavior due to alias #537

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Groxx
Copy link
Contributor

@Groxx Groxx commented Aug 7, 2018

RegisterActivityWithOptions registers an inferred func name into a map containing {inferred-name: registered-name}, I assume to allow you to execute activities with either their registered-name or their function, for simplicity.

Unfortunately this is unsafe - reflected function names are not guaranteed to be unique. And it's relatively easy to encounter if you generate workflow or activity functions (as can easily occur in tests, and could occur IRL as well, though generally you'd just pass those args to a shared activity).


TBH I'm not fond of allowing ambiguous calls like this enables, but that's mostly irrelevant. This silently produces incorrect behavior, which it should not do.

Making it error on duplicate-inferred-names would prevent a silent failure... but it'd also mean you cannot generate activities / workflows at all.
And trying to allow generated activities / workflows while also allowing ambiguous calls doesn't seem easily possible... func addresses would work for anonymous funcs, but for named ones you can only get the address of the var, not the "canonical" one. Maybe something with reflection -> function pointer address?

I dunno. I submit this as evidence of bad behavior, and to trigger discussion.

`RegisterActivityWithOptions` registers an inferred func name into a
map containing `{inferred-name: given-name}`, I assume to allow you to
execute activities with either their given-name or their function, for
simplicity.

Unfortunately this is unsafe - reflected function names are not guaranteed
to be unique.  And it's relatively easy to encounter if you generate
workflow or activity functions (as can easily occur in tests, and could
occur IRL as well, though generally you'd just pass those args to a shared
activity).

---

TBH I'm not fond of allowing ambiguous calls like this enables, but that's
mostly irrelevant.  This silently produces incorrect behavior, which it
should not do.

Making it error on duplicate-inferred-names would prevent a silent failure...
but it'd also mean you cannot generate activities / workflows at all.
And trying to allow generated activities / workflows while also allowing
ambiguous calls doesn't seem easily possible... func addresses would work
for anonymous funcs, but for named ones you can only get the address of the
var, not the "canonical" one.  Maybe something with reflection -> function
pointer address?

I dunno.  I submit this as evidence of bad behavior, and to discuss what it
means for the future.
@meiliang86
Copy link
Contributor

meiliang86 commented Dec 5, 2019

Most people will write the code as the following, and it won't be an issue.

func init() {
	RegisterActivityWithOptions(f1, RegisterActivityOptions{"f1"})
	RegisterActivityWithOptions(f2, RegisterActivityOptions{"f2"})
}

func f1() error {
	return nil
}

func f2() error {
	return nil
}

@Groxx
Copy link
Contributor Author

Groxx commented Dec 6, 2019

Part of the reason I bring this up is that it did bite me in some of my code. Most will do that, sure, but not all.

One area where it's particularly common is if you do any dynamic workflow or activity wrappers. I'm adding context info per request to my activity calls, and initializing a per-request cache, and doing so with a reflection-generated func wrapper that looks something like this:

func Register(ctx, fn, name) {
  wrapped := reflect.MakeFunc(reflect.TypeOf(fn), func(in []reflect.Value) []reflect.Value) {
    ctx := context.WithValue(in[0].Interface().(Context), "cache key", cache{})
    in[0] = reflect.ValueOf(ctx)
    return reflect.Call(reflect.ValueOf(fn), in)
  })
  activity.Register(wrapped, RegisterActivityOptions{"name"})
}

which fits the example test exactly. I make a bunch of activities that, as far as reflection is concerned, are all defined at the same location, so they all get the same inferred name.

@CLAassistant
Copy link

CLAassistant commented Jun 13, 2020

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants