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

Modules fixes #2234

Merged
merged 3 commits into from Nov 12, 2021
Merged

Modules fixes #2234

merged 3 commits into from Nov 12, 2021

Conversation

mstoykov
Copy link
Collaborator

No description provided.

yorugac
yorugac previously approved these changes Nov 11, 2021
Copy link
Contributor

@yorugac yorugac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This renaming looks much neater 👍

na--
na-- previously approved these changes Nov 11, 2021
@na-- na-- added this to the v0.35.0 milestone Nov 11, 2021
type InstanceCore interface {
// InstanceParams is something that will be provided to module instance on initialization so that it can get access to
// everything it needs
type InstanceParams interface {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking for a better name, after which I will rebase it to get rid fixup commits

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following the Go naming convention for interfaces, you would end up with something like ContextRuntimeGetter. Idiom aside, I find InstanceParams explicit enough, although I didn't expect/realize it was an interface until I checked how it was used: when seeing the InstanceParams argument in the NewModuleInstance it wasn't immediately clear it was an interface.

Hope that's helpful 👀

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name seems fine, and is more in line with output extensions. 👍

I'd just make the comment more descriptive. Maybe:

InstanceParams will be provided to module instances on initialization so that they can access internal k6 objects.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ModuleParams ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oleiade the problem is that it will not only be about Getting those 2 or even the actual 4 it''s giving now.

In #2228 this is also the way to add something to the event loop.

In practice it's interacting with k6, predominantly in the context of 1 VU and the current iteration. So something like State would've made sense except for the part that modules.State.AddToEventLoop sounds bad.

_tangent: AddToEventLoop might not be the end method that will be used btw, it might be what currently is named Reserve on the eventloop, which in practice returns a function taking a function (func(func()) where the idea is that it needs to be called to add something to the event loop but at the same time it will block the event loop from ending even if the loop is empty. (It doesn't actually reserve a position in the queue or something like that). Given that the name for that might be modules.State.blockEventLoopUntil or ... something actually better 🤣

@imiric
How about?

InstanceParams will be provided to module instances on initialization so that they can access interact with k6.

Again the eventLoop and the likely additional stuff for an module/VU lifecycle integration will be at least in part, part of this

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yorugac the full name currently is modules.InstanceParams and these are the params for when an instance of the module on each import "nameofmodule" is being evaluated. There currently are no params provided just when we load "nameofmodule" because it's part of the k6 build but isn't actually instanciated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InstanceParams is suitable for the current design. But the thing is, this is not actually an instance's parameters. It's for providing a way for a module instance to access a VU's whereabouts.

I won't say we should call it VUWhereabouts or VUUniverse (you can type it with more Us) 😄 Maybe, it can be something like VUInternals 🤷

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VUInternals seems like the best option so far

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, @mstoykov I meant this params weren't about instance per se... So I'd say 👍 for VUInternals too but: event loop is going to add methods for promises there -- so it won't be internals either
How large would that interface grow?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How large would that interface grow?

Given that it provides a way for the modules to interact with k6, as much as we need it to interact :). The alternative to this growing is to keep adding interfaces that either it implements or the modules.Instance implements so that we can call something on it 🤷

if modV2, ok := mod.(modules.IsModuleV2); ok {
instance := modV2.NewModuleInstance(&moduleInstanceCoreImpl{ctxPtr: i.ctxPtr})
return i.runtime.ToValue(toESModuleExports(instance.GetExports())), nil
if modV2, ok := mod.(modules.Module); ok {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modV2 now sounds ... bad, but I either need to shadow mod or not name one of them mod/module :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just m? 😄 modV2 would be confusing...

@imiric
Copy link
Contributor

imiric commented Nov 11, 2021

LGTM, just minor suggestions. 👍 for making exports explicit.

Copy link
Member

@inancgumus inancgumus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some suggestions.

// GetContext returns internally set field to conform to modules.InstanceCore interface
func (m *InstanceCore) GetContext() context.Context {
// GetContext returns internally set field to conform to modules.InstanceParams interface
func (m *InstanceParams) GetContext() context.Context {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just Context()?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would guess you want to change the interface (currently named modules.InstanceParams) not the test implementation?

// GetInitEnv returns internally set field to conform to modules.InstanceCore interface
func (m *InstanceCore) GetInitEnv() *common.InitEnvironment {
// GetInitEnv returns internally set field to conform to modules.InstanceParams interface
func (m *InstanceParams) GetInitEnv() *common.InitEnvironment {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just Env or InitEnv?

return m.InitEnv
}

// GetState returns internally set field to conform to modules.InstanceCore interface
func (m *InstanceCore) GetState() *lib.State {
// GetState returns internally set field to conform to modules.InstanceParams interface
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

State()?

// GetRuntime returns internally set field to conform to modules.InstanceCore interface
func (m *InstanceCore) GetRuntime() *goja.Runtime {
// GetRuntime returns internally set field to conform to modules.InstanceParams interface
func (m *InstanceParams) GetRuntime() *goja.Runtime {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Runtime()?

@@ -37,7 +37,7 @@ import (

type Metric struct {
metric *stats.Metric
core modules.InstanceCore
core modules.InstanceParams
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an idea.

What about vu as a field name instead of core?

So it'll be natural to type:

state := m.vu.State()

Instead of:

state := m.core.GetState()

Comment on lines 54 to 56
func New() *RootModule {
return &RootModule{}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm going to say would probably be involved and may not be an easy task. And, I'm not deeply knowledgeable about the system and our goals, so this can be a fruitless suggestion, and it might not even work 🤷

Why don't we register in an extension without giving the k6 an instance of the module, like this:

func init() {
	k6modules.Register("k6/x/browser")
}

With this, we won't have to stutter in tests, and we can more natural type something like this:

New(mii)

Instead Of:

New().NewModuleInstance(mii)

So the interface would look like this:

type IsModuleV2 interface {
    New(InstanceCore) Instance
}

In an extension we can say:

type RootModule struct {
    modules.InstanceCore
}

var _ modules.IsModuleV2 = &RootModule{}

func New(m modules.InstanceCore) *RootModule {
	return &RootModule{InstanceCore: m}
}

Instead of:

type (
	RootModule struct{}
	ModuleInstance struct {
		modules.InstanceCore
	}
)

var (
	_ modules.IsModuleV2 = &RootModule{}
	_ modules.Instance   = &ModuleInstance{}
)

func (*RootModule) NewModuleInstance(m modules.InstanceCore) modules.Instance {
	return &ModuleInstance{InstanceCore: m}
}

func New() *RootModule {
	return &RootModule{}
}

Of course, with this, we need to create a struct (RootModule) of a module ourselves. But then again, we can standardize it like RootModule and instantiate it using reflection.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The biggest (and most obvious problem) is that this all si also used for extensions. And while for internal we can have it listed the way it currently works (and likely will still need to work) is that extensions register themselves in a init function and add the RootModule so that we can call the NewModuleInstance from it ... in reality we can just register the New function, but for historical reasons previous to this interface (which is not used by any non-internal extension) you just registered interface{} and then k6 did a bunch of reflect "magic" see #1802, which had a list of problems, the major one of which is ... nobody could understand how it works or why it doesn't work for something or ... why it was needed in some cases.

Hope this explains the problem enough, but I would recommend reading the provided issue.

As well as remove GenerateExports and make module authors to actually
specify exactly what they will export.
Copy link
Member

@na-- na-- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ LGTM

@@ -151,24 +151,25 @@ func (i *InitContext) Require(arg string) goja.Value {
}
}

type moduleInstanceCoreImpl struct {
// TODO this likely should just be part of the initialized VU or at least to take stuff directly from it.
type moduleVUImpl struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just use moduleVU instead of moduleVUImpl?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some hopes I will be working on the TODO above this cycle, and it will just get completely removed

@mstoykov mstoykov merged commit 5b4fe2d into master Nov 12, 2021
@mstoykov mstoykov deleted the modulesFixes branch November 12, 2021 08:44
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.

None yet

6 participants