Some serious confusion Re: workers

Hi,

Thank you for answering a bunch of initial questions I had about workers here https://community.cloudflare.com/t/confused-about-workers/93497

Also, to Cloudflare folks, I love Workers. Thank you so much for thinking forward and with such great ideas.

I have more questions. Still a bit confused about some of the decisions behind Workers…

  1. In the Cloudflare Dashboard, we are able to create Scripts, WASM Modules and KV Namespaces that are not associated with any specific domain via Home->Create Worker (can be used by any domain in our account) So far so good. How come when we go to Domain->Workers we are only able to create new Scripts and not WASM Modules or KV Namespaces? Also, when we create a Worker from Home->Create Worker the script associated with it is given a random name that we can’t change whereas when we create a Script from Domain->Workers we get to name it whatever we want.

  2. Why does the REST API have some powerful and much needed features that are missing in the Worker JS API? For example, the REST API allows us to list all keys with prefix, limit and cursor (important for pretty much every app) as well as update a bunch of keys at once (important for atomicity, even with eventual consistency)

  3. Also, it seems it went from 10ms for the $5 account to 50ms as far as the CPU bandwidth per request. Why 50ms? Why can’t we pay extra for say 300ms? I know that 300ms is a very large chunk of CPU bandwidth but I have no idea how powerful those CPUs are so to me 50ms is a very arbitrary number. Unless you publish the data model behind your decision to limit it to 50ms I cannot say that I understand the reason. It could be a number that is derived based on your (internal) performance SLA for Workers (given N workers share the same hardware and ultimately a finite number of CPU cores/cycles.)

  4. event.waitUntil(): is there a guarantee that it will actually let some already executed async task to continue to run until the Promise is resolved? There must be a limit. What if the Promise is not resolved for 2000 hours? What is the limit before the async task is cancelled? After all, I don’t see how you can even guarantee that a worker can run indefinitely (i.e. 100% uptime) since sooner or later it will fail, but my question is not about that inevitability. My question is about whether or not there is a timeout value that is simply missing in the docs. Btw, I learned about waitUntil from random googling, so I don’t know if it’s still supported, but just in case.

Thank you.

MarcF

Hi!

I’ll go point by point as long as I know the answers. Someone, like @signalnerve, will maybe answer a few more.

You can do it, WASM modules are within each worker’s editor, one of the tabs, since they are bundled together with each script, KV namespaces are in the tabs above the Worker’s home.

You can change it, just click the name when you are in the editor.

First of all you can use the REST API within the Worker’s code, but from what I heard them say they are working on improving that. There will be improvements coming down the road.

I believe you can, Enterprise plans can get custom time as far as I know. Maybe @cs-cf or @michael know more. I also believe that the 50ms is fine for most of the use cases, except if you do intensive calculations. You can go above the 50ms sometimes, not by much, but their limit is soft except if you consistently hit it.

As far as I know it will wait forever, I don’t know if there is a sanity limit after x amount of time. @signalnerve may be able to confirm. I know that normally every 7 days there is a reset for upgrades, once the requests have been resolved.

It’s here: https://workers.Cloudflare.com/docs/reference/workers-concepts/fetch-event-lifecycle/

I would love to see example usage of these:

  • respondWith()
  • waitUntil()
  • passThroughOnException()

Add to the docs, because they seem very useful.

1 Like

That would be great, though you would like them now here? I can give you a code sample.

2 Likes

That would be great :slight_smile:

Simplest example, starting from their Hello World example.

addEventListener('fetch', event => {
  event.passThroughOnException()
  /**
  event.passThroughOnException() makes the fails transparent to the user
  you need to understand if you want to block access on fail, if you do user
  auth for example, or not.
  **/

  event.respondWith(handleRequest(event.request))
  /**
  event.respondWith() is the standard method, only one must run per Workers,
  but there can be more than one with ifs to filter by domain or something.
  You can filter also after it runs, obviously.
  **/
})

/**
 * Fetch and log a request
 * @param {Request} request
 */
async function handleRequest(request) {
  event.waitUntil(someFunction())
  /**
  event.waitUntil() allows to run functions after the response has been
  returned to user. You can use it for logging or putting into the
  cache API, for example.
  **/

  return new Response('Hello worker!', { status: 200 })
}
1 Like

@matteo

Worker editor accessed via Home->Create Worker->ScriptName

Worker editor accessed via MyDomainName->Workers->Launch Editor

You can clearly see absence of the WASM and KV tabs in the second instance, where you can only add Binding to existing WASM/KV resources, not create new ones.

Regarding use of the REST API in Workers. Sorry for not pointing out the obvious. We always have to do that in written communication so as not to confuse. But that the fact that you can call a REST API from JS is a given, I thought. What bugs me is that the REST API is divergent from the JS API available in Workers. Same as with the discrepancy between the ways you can edit a Worker, we have REST API different from Worker JS API. Why? It’s very confusing to me to have the same functionality being presented with two different interfaces that don’t match in terms of feature set. Also, the Cloudflare docs on pricing and limits are still out of date, presenting yet another case of having different presentation of the same thing. Call me a perfectionist, but consistency makes things simple, and inconsistency creates complexity.

As to waitUntil(), NodeJS scripts can always trap system signals but how do you do that in service worker scripts? Is there the equivalent of onbeforeunload event? If CF has to shut down a worker, is there a wait for ne to execute some clean up code before that happens? I believe if you’re going to waitUntil() potentially a long time CF will at some point shut down the process or the server doing the waiting will inevitably fail/exit. CF docs also say the workers do get ejected from time to time. So I think it’s not very responsible to have waitUnti() without having a way to trap a forced exit. Obviously, the server the waiting process runs on could just die suddenly (data center catastrophe) and no way to react to that, but at least in case it is ejected by CF including for inadvertently running over the 50ms limit consistently (runaway loop etc) we need to be able to run some code to handle things properly before the process is exited.

Your thoughts?

The KV namespace is on the Workers tab, before launching the editor (it was there even before the change to the multi-script), the binding for the WASM can be added, click on it.

Because most likely they are two different subsystems, the JS interface needs to be done and there is little request (except for maybe search?) for doing so. And there is an easy alternative.

I already pointed that out to them, I don’t know why it wasn’t fixed.

You can’t, because it’s not Node.js.

No.

Of course, but workers isn’t really designed to run for hours on end. The limit before was set to 30 total seconds.

I won’t quote everything, but Workers isn’t done to substitute long running programs, use other cloud services, run your own server. You can aggregate responses, that’s for sure, but within a few tens of seconds. See Scott Helme’s Report URI implementation for example.

I believe you are treating Cloudflare’s Workers as a substitution to full Node functions. They are only to a certain extent, not for extremely long running processes, not for programs that can’t withstand a bad termination.

Thanks, I’ll test it tomorrow :slight_smile:

1 Like

I see that. Not sure why it’s not in the editor. Still, the WASM tab is missing in this case. I mean, not nitpicking per se, just trying to be helpful so maybe one of their people would read this and see if they can reconcile the two different UX they have for editing workers, without telling people to use Wrangler instead.

I agree that both need to exist (as you say “two different subsystems”) but it would reduce cognitive load to have them simply mirror each unless there is a good reason for making them different (more cognitive load)

It’s not a tab per se, but simply click “add binding” exactly where you took the screenshot before. That will allow you to upload.

The new UI is better, I agree. I would probably show only that.

I wan’t trying to convince you of that, but I presume that implementing that in JS is complex and it’s not worth it for the requests they have.

It’s not. Happy to share an implementation of ‘keys’ function as JS API (not my own, just found it randomly while googling, which is how I realized there is a REST API to start with) Will post later today once I dig it up.

As far as coding it in JS I know it’s not, but I have no clue how their backend is implemented.

Why can’t it be simply calling the REST API from JS? do they have a better way than REST e.g. grpc? Either way, the JS side would be the same above the REST/grpc calls.

https://gist.github.com/anywhichway/7941a747441c2924cbd141334edc1d75#file-keys-js

https://gist.github.com/anywhichway/285ee12ebc987410db7b8f01bb73118f#file-keysexample-js

EDIT:

I meant CF should include this and other functions currently available only in the REST API in the Workers JS API by preloading as a library.

Hi all - apologies for the delay in responding, had a long weekend here in the US!

I think this is specifically a question about Workers KV, right? There is currently no support for listing keys in the JS API - the team is aware that there’s a lot of demand for it, but right now, listing keys is only supported via the REST API. Sorry about that!

Using waitUntil, you have thirty seconds to make any additional requests inside of the Workers script. This is good for things like logging, analytics, etc, not long-running requests. More on that in the docs.

2 Likes

Hey there folks, a bit of clarification about the API/JS discrepancy, especially from the perspective of KV:

We build out functionality in the API first, and then later, add it to the JS API. So for example, in the list case, we hadn’t even announced that list was available yet; you just happened to pay close attention :slight_smile:

But, this gets to the deeper question: why are they different at all?

In some cases, it is true that there hasn’t been demand for the API from JS yet, and we’re working on other things. But at least with KV, that’s not only the case. So for example, take LIST operations, as you’ve pointed out. The API is clearly going the whole way back to the origin, since you’re calling it directly. If you’re inside a worker, well, the hope is that a significant amount of time, you don’t need to contact the origin, as that’s kinda the point of the edge in the first place! This means that in the JS API, we have some runtime features that will cache requests, stuff like that. This means that the JS API will be better for you than calling the HTTP API directly, but it also means it takes us some time to build the feature out, decide the exact way it works, etc. This is easier for some features than others. In this case, to be clear, we do plan on offering LIST stuff from the JS API, the implementation just isn’t finished yet.

I also very much understand that the discrepancy can be confusing, but we feel that releasing the API first, even when the JS side isn’t done, means that people who really need these kinds of features can start using them today, even if they’re not as performant from the edge as we’d may like. We could hold back the API until the JS stuff is done, and it would be more consistent, but we like to ship stuff to users sooner.

Does that make sense? Sorry that it’s not more clearly communicated previously.

2 Likes

Thanks for the clarification Steve!

I wasn’t that far out then, good to know!

1 Like

That’s good to know… thanks for the context and info on that!

Ah. Yes. Ok. Yeah it does make sense provided that us developers realize the reason for it :slight_smile: I would add it somewhere upfront in the JS API docs so we all understand that it be lagging behind, for a very good reason.

I didn’t realize that the REST API goes all the way to the central store. I guess I can think of it as CF’s internal API that CF decided to share with us. I assume that in case of write operations the REST API writes to the central store and the JS API writes to the edge and writes from edge are propagated? Any plans for DHT type store?

Thank you for engaging around this. I appreciate it,

@sklabnik

This is very important for us to understand. I’m conflicted now wether to use REST API or JS API to write to KV. It depends on each scenario. I assume if I want the write to be serializable (in the distributed systems sense) then I should write to the central store (via the REST API) but I also have scenarios where I can work with eventual consistency so I can use the JS API? Is this accurate and what are the tradeoffs of REST vs JS API when it comes to writes?