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

Question: sockets example? #34

Closed
ydnar opened this issue Jun 1, 2023 · 16 comments
Closed

Question: sockets example? #34

ydnar opened this issue Jun 1, 2023 · 16 comments
Labels

Comments

@ydnar
Copy link
Contributor

ydnar commented Jun 1, 2023

Hi there, pardon if this isn’t the right place to ask a question…

Thanks for building this! Yesterday I was able to build and run a reasonable chunk of our stack with WASI after patching a few pieces (filesystem access, a few upstream dependencies without wasm/wasip1 compatibility), and immediately ran into the fake net package that’s currently shipping in gotip.

Would love to continue grinding on this so our stack can be—at least partially—deployed into a WASM/Wasi environment.

  1. Do you have any examples of using the wasmedge socket interface in this package?
  2. Where’s a good place to start to weld ^^ onto Go net package semantics?

Thanks!

@chriso
Copy link
Contributor

chriso commented Jun 2, 2023

Great question! Go in v1.21 will support vanilla WASI preview 1, which has only limited networking capabilities. Specifically, you can only interact with a pre-opened socket file descriptors via net.FileListener and net.FileConn (see golang/go@a17de43 and https://gist.github.com/chriso/6c71e968ef1002981a6ff46ceaa39ee3). You cannot create sockets with WASI preview 1.

This library provides a WasmEdge sockets extension, and may support other socket extensions in future (e.g. WASIX via #32). It sets up the WebAssembly runtime on the host side with the necessary system call implementations, but the guest (in this case, Go with GOOS=wasip1) is missing them.

There are two options:

  1. when compiling your application, set GOROOT to the Go version found in https://github.com/stealthrocket/go/pull/2, where we've implemented the extra system calls on the guest side. We are working on getting this upstreamed in some form so that Go has native support for creating sockets. With this approach, no changes are required to your Go application.
  2. use an alternative net package, one that has alternative implementations of Listen and Dial that make the necessary system calls and then setup a net.Listener and net.Conn backed by either net.FileListener or net.FileConn. We may will offer a https://github.com/stealthrocket/net package soon that does this. With this approach, you'll need to inject the net.Dial function or net.Listener implementation into higher-level components in your application, for example when making HTTP requests or connecting to databases.

This is still a rapidly evolving area so we'd appreciate any feedback you have 😄

I should add that these issues affect Go only. You should (in theory) be able to compile applications from other languages (e.g. C/C++/Rust/Zig) and get full networking support.

@ydnar
Copy link
Contributor Author

ydnar commented Jun 2, 2023

Ah, makes sense. We’re using gotip for 1.21 features, including the pre-opened fd listeners. Thanks for the CLs!

One tricky bit is that net.Dialer isn’t an interface, and a few packages we use require a concrete net.Dialer, as opposed to something that implements DialContext.

What do you think the odds are that stealthrocket/go#2 lands in 1.21? Is it possible to extract that into an alternative net package?

@ydnar
Copy link
Contributor Author

ydnar commented Jun 2, 2023

This is new: https://github.com/tetratelabs/wazero/releases/tag/v1.2.0

Looks like built-in support for pre-opened sockets: tetratelabs/wazero#1493

@chriso chriso added the sockets label Jun 11, 2023
@achille-roussel
Copy link
Contributor

Hello @ydnar!

We open-sourced https://github.com/stealthrocket/net which has a net.Dial and net.Listen function working with socket extensions compatible with WasmEdge and https://github.com/stealthrocket/wasi-go

Let us know if this is useful and if you have any feedback!

@ydnar
Copy link
Contributor Author

ydnar commented Jun 13, 2023

Nice! I'll check it out.

What are your thoughts on WASIX?

@achille-roussel
Copy link
Contributor

achille-roussel commented Jun 13, 2023

On WASIX, we love that important industry actors are trying to innovate and create experiments to enable more and more applications to run on WebAssembly.

We've started a spike on adding ABI support for WASIX sockets in wasi-go #44

At first, it seems like the WASIX ABI footprint is all-or-nothing, programs compiled to WASIX easily take dependencies on threads and other extensions, which makes it a challenge to adopt incrementally. We're gonna keep investigating and help where we can, interoperability is an amazing feature of WASM so the more we can make systems compatible with one another the better!

@ydnar
Copy link
Contributor Author

ydnar commented Jun 13, 2023

On the subject of threads, what's the current state of wasi-go with respect to non-blocking IO and goroutines?

@achille-roussel
Copy link
Contributor

wasi-go has full non-blocking support, a Go program compiled with GOOS=wasip1 will be able to do cooperative scheduling and dispatch I/O to goroutines just like any other target gang Go compiled to.

We still have a CL that needs to be merged in Go to enable non-blocking on stdio https://go-review.googlesource.com/c/go/+/498196, if you're interested in seeing this happen in 1.21 you could chime in there and voice your support for the change!

@ydnar
Copy link
Contributor Author

ydnar commented Jun 13, 2023

Will do.

Would love to nudge this along more: https://go-review.googlesource.com/c/go/+/500576

@achille-roussel
Copy link
Contributor

Ah yeah! This first attempt isn't going to make it but we have an alternative, stay tuned!

@ydnar
Copy link
Contributor Author

ydnar commented Jun 14, 2023

I got this working with a proxy package that substitutes net/wasip1 primitives for net, but it’s unable to open sockets to localhost with this error:

dial tcp 0.0.0.0:6379: context deadline exceeded

(Note: this is to 127.0.0.1:6379, without having to resolve localhost) Is there a command line flag to wasirun that enables this?

The commands I’m using to build and run:

wasm: dist-dir go.sum tools $(go_source) $(resource_files)
	GOOS=wasip1 GOARCH=wasm CGO_ENABLED=0 gotip build -ldflags "$(GO_LDFLAGS)" -o $(wasm_binary)

wasm-run: $(wasm_binary)
	wasirun --non-blocking-stdio --sockets auto --listen 127.0.0.1:8080 $(wasm_binary)

@achille-roussel
Copy link
Contributor

Would you happen to be able to share the code snippet for your application so we can reproduce the issue?

@ydnar
Copy link
Contributor Author

ydnar commented Jun 14, 2023

We’re using github.com/gomodule/redigo/redis to create a connection pool. It has a config option to override DialContext, which uses our wnet.DialContext, which is aliased to wasip1.DialContext.

pool := &redis.Pool{
	MaxIdle:     64,
	MaxActive:   128,
	IdleTimeout: 5 * time.Minute,
	DialContext: func(ctx context.Context) (redis.Conn, error) {
		options := []redis.DialOption{
			redis.DialContextFunc(wnet.DialContext),
			redis.DialConnectTimeout(redisConnectTimeout),
			redis.DialReadTimeout(redisReadTimeout),
			redis.DialWriteTimeout(redisWriteTimeout),
			redis.DialPassword(password),
		}
		return redis.DialContext(ctx, platform.TCP, addr, options...)
	},
	TestOnBorrow: func(conn redis.Conn, t time.Time) error {
		if time.Since(t) < time.Minute {
			return nil
		}
		_, err := conn.Do("PING")
		return err
	},
}

wnet_wasip1.go:

//go:build wasip1

package wnet

import "github.com/stealthrocket/net/wasip1"

// Dialer implements Dial and DialContext.
type Dialer = wasip1.Dialer

// DialContext opens a new net.Conn.
var DialContext = wasip1.DialContext

// Listen opens a net.Listener.
var Listen = wasip1.Listen

wnet_unix.go:

//go:build unix

package wnet

import "net"

// Dialer implements Dial and DialContext.
type Dialer = net.Dialer

// DialContext opens a new net.Conn.
var DialContext = (&net.Dialer{}).DialContext

// Listen opens a net.Listener.
var Listen = net.Listen

@ydnar
Copy link
Contributor Author

ydnar commented Jun 16, 2023

I disabled SIGTERM handling, which fixed the server request latency, allowing me to debug the networking code.

	if runtime.GOOS != "wasip1" {
		signal.Notify(done, os.Interrupt, syscall.SIGTERM)
	}

@chriso
Copy link
Contributor

chriso commented Jun 16, 2023

@ydnar try running wasirun with wasirun --trace to see what system calls are made.

@ydnar
Copy link
Contributor Author

ydnar commented Jun 23, 2023

This is working great. Closing, thanks for your help!

@ydnar ydnar closed this as completed Jun 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants