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

Frequent "Promise will never complete" and "call to released function" errors in the fetch example #57

Open
HouzuoGuo opened this issue May 20, 2023 · 5 comments

Comments

@HouzuoGuo
Copy link

Hey.
I'm running the fetch example (_examples/fetch/main.go) under a free worker plan. When making about 2-3 requests per second the example works quite well, however, when the request rate increases to about 5 request per second the example starts to run into these errors:

...
GET https://first.hzgl.workers.dev/fetchexample - Ok @ 5/20/2023, 6:03:26 PM
GET https://first.hzgl.workers.dev/fetchexample - Exception Thrown @ 5/20/2023, 6:03:26 PM
✘ [ERROR]   Error: The script will never generate a response.
GET https://first.hzgl.workers.dev/fetchexample - Exception Thrown @ 5/20/2023, 6:03:26 PM
  (error) call to released function
✘ [ERROR]   Error: Promise will never complete.
GET https://first.hzgl.workers.dev/fetchexample - Ok @ 5/20/2023, 6:03:26 PM
...
@syumai
Copy link
Owner

syumai commented May 21, 2023

I'll check this later, thanks!

@AdjectiveAllison
Copy link
Contributor

I have a similar thing going on -- below is relevant data thus far:

I set wrangler to local mode in order to see the errors.

[mf:inf] Worker reloaded! (1.06MiB)
[mf:wrn] Worker's uncompressed size exceeds the 1MiB limit! Note that your worker will be compressed during upload so you may still be able to deploy it.
[mf:inf] Listening on 0.0.0.0:8787
[mf:inf] - http://127.0.0.1:8787
[mf:inf] Updated `Request.cf` object cache!
panic: unimplemented: (reflect.Type).NumMethod()
[mf:err] Unhandled Promise Rejection: RuntimeError: unreachable
    at runtime._panic (wasm://wasm/00429132:1:7424)
    at (reflect.rawType).NumMethod (wasm://wasm/00429132:1:16538)
    at encoding/json.indirect (wasm://wasm/00429132:1:247803)
    at (*encoding/json.decodeState).value (wasm://wasm/00429132:1:240398)
    at main.main$1 (wasm://wasm/00429132:1:357508)
    at github.com/syumai/workers.handleRequest$1 (wasm://wasm/00429132:1:343023)
    at github.com/syumai/workers.handleRequest$1$gowrapper (wasm://wasm/00429132:1:342583)
    at tinygo_rewind (wasm://wasm/00429132:1:1903)
    at (*internal/task.Task).Resume (wasm://wasm/00429132:1:38562)
    at runtime.scheduler (wasm://wasm/00429132:1:133061)

Here is my code(It's hacked together from multiple of your examples @syumai)
I'm unsure if I'm using the right cloudflare tools for the job I'm doing but I'm just pasting the information in case it is helfpul :)


import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"

	"github.com/syumai/tinyutil/httputil"
	"github.com/syumai/workers"
	"github.com/syumai/workers/cloudflare"
)

type TokenResponse struct {
	AccessToken string `json:"access_token"`
	ExpiresIn   int    `json:"expires_in"`
}

const kvNamespace = "twitch"
const tokenAccessKey = "accessToken"
const tokenExpiresKey = "tokenExpires"

func main() {
	workers.Serve(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		if req.URL.Path != "/" {
			w.WriteHeader(http.StatusNotFound)
			return
		}

		clientID := cloudflare.Getenv(req.Context(), "client_id")
		clientSecret := cloudflare.Getenv(req.Context(), "client_secret")

		data := url.Values{}
		data.Set("client_id", clientID)
		data.Set("client_secret", clientSecret)
		data.Set("grant_type", "client_credentials")

		// initialize KV namespace instance
		kv, err := cloudflare.NewKVNamespace(req.Context(), kvNamespace)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("failed to init KV: " + err.Error()))
			return
		}

		res, err := httputil.PostForm("https://id.twitch.tv/oauth2/token", data)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("failed to make request: " + err.Error()))
			return
		}

		defer res.Body.Close()
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("failed to read response: " + err.Error()))
			return
		}

		var tokenResponse TokenResponse
		err = json.Unmarshal(body, &tokenResponse)
		if err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("failed to unmarshal response: " + err.Error()))
			return
		}

		kv.PutString(tokenAccessKey, tokenResponse.AccessToken, nil)
		kv.PutString(tokenExpiresKey, strconv.Itoa(tokenResponse.ExpiresIn), nil)
	}))
}

@AdjectiveAllison
Copy link
Contributor

I think it's likely my use of encoding/json and tinygo not having reflect fully implemented yet(although it looks like we're closer to having it) --- tinygo-org/tinygo#2660

I'm unsure if it's similar for your fetch example. I attempted to unmarshal into a map instead of a struct and I still get the reflection error. I'm still digging currently though.

@AdjectiveAllison
Copy link
Contributor

Yep, that ended up being exactly what it was. I attempted to use json.Decode instead of unmarshal but I think it still uses reflect under the hood somewhere. I removed encoding/json and implemented my own json parser for the specific section I was in and it ran well right away locally. I then published my code and was able to get 15 requests per second handled without any errors in production workers.

Here was the final sizing of my uploaded package - Total Upload: 844.29 KiB / gzip: 272.16 KiB

@syumai
Copy link
Owner

syumai commented May 26, 2023

@AdjectiveAllison
In the upcoming release of TinyGo (v0.28), which is expected to be released soon, many features of the reflect package are expected to be supported. It appears that a significant number of functionalities in the encoding/json package, which are currently not working, will also start working. I believe that your sample code will also start working. I have been keeping an eye on the progress of TinyGo, and if encoding/json starts working, I plan to update the example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants