-
Notifications
You must be signed in to change notification settings - Fork 10
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
Async host functions in ForegroundPlugin #82
Comments
I brought this up with the team and we probably aren't interested in adding this to Extism. We are waiting on and following Wasm async standardization and community efforts and we'll likely chose one of them for Extism 2.0, but do not want to lock Extism to a specific async mechanism for the time being. https://v8.dev/blog/jspi https://github.com/WebAssembly/js-promise-integration/blob/main/proposals/js-promise-integration/Overview.md However, if you implement async system like this just for your own usage, please share it with us! |
Thanks for reply! the commuity proposal is absolutely the best approach, but I can't wait for it, it's looks like unsuable whthin this year :( I understood the team considerations, so I'm implementing in my application, basically is a chain of callbacks, then notify result in async. very similar to async.series. If not support concurrency, is not that hard to implement. |
Here is the basic example: main.go package main
import "github.com/extism/go-pdk"
func main() {
}
//go:wasmimport async invoke
func asyncInvoke(uint64) uint64
//export run
func run() int32 {
println("go run")
makeAsyncCall(&AsyncCall{
Method: "Example",
Data: "From GO",
Cb: func(err error, data string) {
println("go callback", data)
makeAsyncCall(&AsyncCall{
Method: "M2",
Data: "From GO 2",
Cb: func(err error, data string) {
println("go callback", data)
},
})
},
})
return 0
}
type AsyncCall struct {
Method string
Data string
Id uint64
Cb func(err error, data string)
}
var callIdCounter uint64 = 0
var currentCalls = make(map[uint64]*AsyncCall)
func makeAsyncCall(call *AsyncCall) {
callIdCounter++
call.Id = callIdCounter
req, err := pdk.AllocateJSON([]any{
call.Method,
call.Id,
call.Data,
})
if err != nil {
panic(err)
}
currentCalls[call.Id] = call
asyncInvoke(req.Offset())
}
//export asyncResult
func asyncResult() uint64 {
input := [2]any{}
err := pdk.InputJSON(&input)
if err != nil {
return 0
}
var id uint64 = uint64(input[0].(float64))
println("go asyncResult", id, input[1])
call := currentCalls[id]
call.Cb(nil, input[1].(string))
delete(currentCalls, call.Id)
return 0
} test.ts import createPlugin, {CurrentPlugin} from "@extism/extism";
(async() => {
const p = await createPlugin({
wasm: [
{path: './callback.wasm', name: 'main'}
],
}, {
useWasi: true,
enableWasiOutput: true,
functions: {
async: {
invoke: (cp: CurrentPlugin, offset: bigint) => {
const [method, id, param] = cp.read(offset)!.json()
console.log(`js called method: ${method}, callId: ${id}, param: ${param}`)
setTimeout(async() => {
await p.call('asyncResult', JSON.stringify([id, `js result, go req: ${param}`]))
}, 100)
return 0n
}
}
}
})
const instant = await p.getInstance()
await p.call("run")
})() test output:
todo:
|
My app had ready wrap all operations into single one protobuf message, so it's very easy to port. |
As the discord thread, I'm not sure this is suitable for other languages, so I create the issue first on js-sdk.
Use BackgroundPlugin to support async host functions had more overhead and limitations, and async result not just used for HTTP requests, maybe a simple db query and IO operations which cannot be synced Node.js.
Flowgram:
The call id maybe unnecessery if we don't planning to support concurrency.
So now we can use async host fucntion in ForegroundPlugin, with no overhead and new thread, easy to control and maintain.
The text was updated successfully, but these errors were encountered: