-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Modules fixes #2234
Conversation
There was a problem hiding this 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 👍
js/modules/modules.go
Outdated
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 { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 👀
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ModuleParams
?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
🤷
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 🤷
js/initcontext.go
Outdated
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 { |
There was a problem hiding this comment.
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
:(
There was a problem hiding this comment.
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...
LGTM, just minor suggestions. 👍 for making exports explicit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some suggestions.
js/modulestest/modulestest.go
Outdated
// 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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just Context()
?
There was a problem hiding this comment.
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?
js/modulestest/modulestest.go
Outdated
// 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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just Env
or InitEnv
?
js/modulestest/modulestest.go
Outdated
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
State()
?
js/modulestest/modulestest.go
Outdated
// 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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Runtime()
?
js/modules/k6/metrics/metrics.go
Outdated
@@ -37,7 +37,7 @@ import ( | |||
|
|||
type Metric struct { | |||
metric *stats.Metric | |||
core modules.InstanceCore | |||
core modules.InstanceParams |
There was a problem hiding this comment.
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()
func New() *RootModule { | ||
return &RootModule{} | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
2cd7f24
to
5efd660
Compare
There was a problem hiding this 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 { |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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
No description provided.