-
Notifications
You must be signed in to change notification settings - Fork 600
Open
Description
Error occurs when invoking the same JS function concurrently via multiple goroutines.
Here the code:
func IfJs() string {
return `function callIf(i) {
var g = i == 1;
if (g) {
i = i + 1;
}
return i;
}
`
}
func TestIfFuncJsParal(t *testing.T) {
javascriptVM := New()
_, err := javascriptVM.Run(IfJs())
require.NoError(t, err)
paral := 100
wg := sync.WaitGroup{}
wg.Add(paral)
for i := 0; i < paral; i++ {
go func() {
defer wg.Done()
f, err := javascriptVM.Get("callIf")
require.NoError(t, err)
_, err = f.Call(f, 1)
require.NoError(t, err)
}()
}
wg.Wait()
}
Here the ERROR:
fatal error: concurrent map writes
Description:
The root issue stems from how compiled callIf functions become nodeFunctionObject instances, each holding a pointer to a same runtime object (constructed via New()). When the Call method executes:
- The function scope is assigned to the runtime.scope field.
- Concurrent goroutines sharing the same runtime end up accessing:
The same scope
The same stash
The same underlying map
This creates unsafe concurrent map access when storing variables, triggering the observed race conditions.
Proposed Solutions
Option 1: ThreadLocal Isolation
Pros: Explicit scope isolation
Cons:
- Introduces external dependencies
- Anti-pattern in Go
Option 2: Context-Based Scope Passing
- Avoid shared scope by storing scope in context
- Built-in cancellation support via context
Request for Feedback
Which approach would better align with otto’s design philosophy? Are there alternative patterns worth considering?
Metadata
Metadata
Assignees
Labels
No labels