-
Notifications
You must be signed in to change notification settings - Fork 244
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
experimental: adds close notification hook (#1574)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
- Loading branch information
1 parent
326c267
commit 0300f4b
Showing
10 changed files
with
201 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package experimental | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/tetratelabs/wazero/internal/close" | ||
) | ||
|
||
// CloseNotifier is a notification hook, invoked when a module is closed. | ||
// | ||
// Note: This is experimental progress towards #1197, and likely to change. Do | ||
// not expose this in shared libraries as it can cause version locks. | ||
type CloseNotifier interface { | ||
// CloseNotify is a notification that occurs *before* an api.Module is | ||
// closed. `exitCode` is zero on success or in the case there was no exit | ||
// code. | ||
// | ||
// Notes: | ||
// - This does not return an error because the module will be closed | ||
// unconditionally. | ||
// - Do not panic from this function as it doing so could cause resource | ||
// leaks. | ||
// - While this is only called once per module, if configured for | ||
// multiple modules, it will be called for each, e.g. on runtime close. | ||
CloseNotify(ctx context.Context, exitCode uint32) | ||
} | ||
|
||
// ^-- Note: This might need to be a part of the listener or become a part of | ||
// host state implementation. For example, if this is used to implement state | ||
// cleanup for host modules, possibly something like below would be better, as | ||
// it could be implemented in a way that allows concurrent module use. | ||
// | ||
// // key is like a context key, stateFactory is invoked per instantiate and | ||
// // is associated with the key (exposed as `Module.State` similar to go | ||
// // context). Using a key is better than the module name because we can | ||
// // de-dupe it for host modules that can be instantiated into different | ||
// // names. Also, you can make the key package private. | ||
// HostModuleBuilder.WithState(key any, stateFactory func() Cleanup)` | ||
// | ||
// Such a design could work to isolate state only needed for wasip1, for | ||
// example the dirent cache. However, if end users use this for different | ||
// things, we may need separate designs. | ||
// | ||
// In summary, the purpose of this iteration is to identify projects that | ||
// would use something like this, and then we can figure out which way it | ||
// should go. | ||
|
||
// CloseNotifyFunc is a convenience for defining inlining a CloseNotifier. | ||
type CloseNotifyFunc func(ctx context.Context, exitCode uint32) | ||
|
||
// CloseNotify implements CloseNotifier.CloseNotify. | ||
func (f CloseNotifyFunc) CloseNotify(ctx context.Context, exitCode uint32) { | ||
f(ctx, exitCode) | ||
} | ||
|
||
// WithCloseNotifier registers the given CloseNotifier into the given | ||
// context.Context. | ||
func WithCloseNotifier(ctx context.Context, notifier CloseNotifier) context.Context { | ||
if notifier != nil { | ||
return context.WithValue(ctx, close.NotifierKey{}, notifier) | ||
} | ||
return ctx | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package experimental_test | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/tetratelabs/wazero/experimental" | ||
) | ||
|
||
var ctx context.Context | ||
|
||
// This shows how to implement a custom cleanup task on close. | ||
func Example_closeNotifier() { | ||
closeCh := make(chan struct{}) | ||
ctx = experimental.WithCloseNotifier( | ||
ctx, | ||
experimental.CloseNotifyFunc(func(context.Context, uint32) { close(closeCh) }), | ||
) | ||
|
||
// ... create module, do some work. Sometime later in another goroutine: | ||
|
||
select { | ||
case <-closeCh: | ||
// do some cleanup | ||
default: | ||
// do some more work with the module | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package experimental_test | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/tetratelabs/wazero/experimental" | ||
"github.com/tetratelabs/wazero/internal/close" | ||
"github.com/tetratelabs/wazero/internal/testing/require" | ||
) | ||
|
||
// testCtx is an arbitrary, non-default context. Non-nil also prevents linter errors. | ||
var testCtx = context.WithValue(context.Background(), struct{}{}, "arbitrary") | ||
|
||
func TestWithCloseNotifier(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
notification experimental.CloseNotifier | ||
expected bool | ||
}{ | ||
{ | ||
name: "returns input when notification nil", | ||
expected: false, | ||
}, | ||
{ | ||
name: "decorates with notification", | ||
notification: experimental.CloseNotifyFunc(func(context.Context, uint32) {}), | ||
expected: true, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
tc := tt | ||
t.Run(tc.name, func(t *testing.T) { | ||
if decorated := experimental.WithCloseNotifier(testCtx, tc.notification); tc.expected { | ||
require.NotNil(t, decorated.Value(close.NotifierKey{})) | ||
} else { | ||
require.Same(t, testCtx, decorated) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Package close allows experimental.CloseNotifier without introducing a | ||
// package cycle. | ||
package close | ||
|
||
import "context" | ||
|
||
// NotifierKey is a context.Context Value key. Its associated value should be a | ||
// Notifier. | ||
type NotifierKey struct{} | ||
|
||
type Notifier interface { | ||
CloseNotify(ctx context.Context, exitCode uint32) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters