ably-js icon indicating copy to clipboard operation
ably-js copied to clipboard

Add Cloudflare worker support

Open jcapogna opened this issue 4 years ago • 9 comments

I'm aware of the issues in #756 and I am using ably 1.2.3.

After downgrading from latest to 1.2.3, I am experiencing a different problem.

I am getting the following error when running wrangler publish:

Error: Something went wrong! Status: 400 Bad Request, Details {
  "result": null,
  "success": false,
  "errors": [
    {
      "code": 10021,
      "message": "Uncaught Error: Some functionality, such as asynchronous I/O, timeouts, and generating random values, can only be performed while handling a request.\n  at line 34 in nextTick\n  at line 34 in u.requestState\n  at line 34 in t.connect\n  at line 34 in e.connect\n  at line 34 in e\n  at line 22\n  at line 1 in n\n  at line 22\n  at line 1 in n\n  at line 22\n"
    }
  ],
  "messages": []
}

The minimal code required to trigger this error is importing Ably: import * as Ably from "ably"

┆Issue is synchronized with this Jira Task by Unito

jcapogna avatar May 18 '21 22:05 jcapogna

I'm now testing the main branch including the webworker support added in #756.

Importing the webworker version of Ably as follows does not trigger this problem anymore: import * as Ably from 'ably/browser/static/ably-webworker.min'

However, initializing Ably.Realtime does: const ably = new Ably.Realtime("KEY");

jcapogna avatar May 27 '21 22:05 jcapogna

Hi @jcapogna, yeah this is expected; unfortunately the library still won't work in Cloudflare workers. It should now work in a regular webworker context but Cloudflare workers doesn't support XmlHttpRequest (which ably-js uses to make HTTP requests) so we need to do some additional work to support this platform. We'll use this issue to track progress and I hope we can get it resolved for you soon.

owenpearson avatar May 28 '21 08:05 owenpearson

Thanks @owenpearson. Do you know if this affects the REST client in addition to the Realtime client?

jcapogna avatar May 28 '21 16:05 jcapogna

@jcapogna Yeah it does affect the REST client as well unfortunately. If you don't mind the extra effort you can always use the REST API directly with the fetch API (or any other HTTP client which uses fetch under the hood) in the meantime while we're working on solving this issue.

owenpearson avatar May 28 '21 16:05 owenpearson

Good suggestion @owenpearson. Using the REST API might not be too bad for my use case.

jcapogna avatar May 28 '21 16:05 jcapogna

I'm able to create token requests by using the Ably Rest client in Cloudflare Workers, you can see my code here: https://github.com/ben-xD/ably-cloudflare-workers

I faced some quirks with cloudflare workers: mainly the handler passed as 2nd argument to addEventListener cannot be an async function. My API is functioning normally and sending token requests back to the client.

~~Unfortunately, on the free plan CPU execution time is capped to 10ms, and perhaps this is not enough, because the response is not sent back to the client. I confirmed the token is created on the worker by using wrangler tail and viewing the logs though. Do you have a paid Cloudflare account @jcapogna ?~~

ben-xD avatar May 29 '21 21:05 ben-xD

@ben-xD I'm able to do the same. I can use the Ably Rest client in a Cloudflare Worker to invoke ably.auth.createTokenRequest(), which successfully creates a token request.

The Rest client does not work when using it to retrieve channel history. At least in this example.

The code:

import { Rest } from 'ably/promises'

const ably = new Rest({ key: API_KEY });

const channel = ably.channels.get(CHANNEL_NAME);
const messages = await channel.history({ limit: 1 });

Invoking channel.history() results in this error:

TypeError: t.Request is not a function

This seems like the other Cloudflare Worker problem you were having.

I also tried the callback version of the Ably Rest client. That gave me the following error when calling channel.history():

A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve, but has detected that the Promise cannot possibly ever resolve because all code and events related to the Promise's request context have already finished

jcapogna avatar May 29 '21 23:05 jcapogna

Do you have an async handler for addEventListener? Your error might be related to this SO question/ answer I posted: https://stackoverflow.com/questions/67756143/cloudflare-worker-times-out-for-the-client-but-all-the-work-completes-and-no-ti/67756144#67756144

ben-xD avatar May 29 '21 23:05 ben-xD

I don't think that's the issue.

Here's a repository where I've reduced it down to a minimal example of createTokenRequest working and channel.history failing.

https://github.com/jcapogna/ably-cloudflare-worker-example/blob/master/src/handler.ts

Note that I'm using ably-js 1.2.4. The latest version gave me other errors.

jcapogna avatar May 30 '21 00:05 jcapogna