Oh awesome. Cloudflare Workers dev environment leaves something to be desired. Does this run in the same JS engine Cloudflare uses (V8 Chrome)? The particular subset of web standards that Cloudflare supports can be tricky to work around.
Is there any support for emulating the CPU runtime limitations that Cloudflare imposes (10ms or 50ms for paid plans)?
Miniflare author here. Miniflare uses the Node VM module (https://nodejs.org/api/vm.html#vm_class_vm_script) which is slightly higher level than V8 isolates used by Cloudflare Workers, but the same underlying engine.
Without low level isolate support in Node, it would be difficult to emulate CPU time limitations. Miniflare will report how long requests take, but this includes I/O time.
I think the hard limit CF imposes is of wall-clock time, not CPU time specifically. The CPU-time limit is a soft limit (i.e. not something that kills your Worker; only something used after-the-fact to determine whether your Worker “gets to succeed”.)
From their docs:
> Cloudflare will bill for Duration charges based on the higher of your wall time or CPU time, with a multiple applied to the CPU time to account for the processing power allotted to your script. We will not bill for wall time Duration charges beyond the execution limit given.
I think what this means in practice (as someone who has tried to implement similar “user workload total-resource-spend limiting” before) is that CloudFlare
1. Start a wall-clock timer, and a CPU-accounting sampler, when the task begins;
2. let the workload run until either it completes, or the timer goes off (and if the timer goes off, the task is hard-killed);
3. If the task was hard-killed, the load-balancing layer is then responsible for responding with a 503 (or whatever error CF uses for this case);
4. If the task wasn’t hard-killed, CF calculate CPU-seconds spent as the area under the curve of CPU-usage * wall-clock-time, and check whether the workload exceeded its CPU budget;
5. If the workload did exceed its budget, then — even though the request was calculated successfully — they nevertheless toss the result away, and reply with a 503 (or whatever) from the Workers control-plane layer;
6. If it didn’t, then they actually forward the result of your request back to the user.
(Meanwhile, handling memory limits is a lot easier — they can just ride the coattails of V8’s own per-ExecutionContext memory accounting, to trigger an OOM event on allocation when area-under-the-curve of GB-secs goes over-limit. But, as a workload might do all its allocations at the beginning and then exceed the memory GB-seconds limit due to the time component increasing, you need to do one final calculation of this at the same time you’re doing the final CPU-accounting check.)
> I think the hard limit CF imposes is of wall-clock time, not CPU time specifically.
No, it's the other way around. The enforced limit is strictly on CPU time, not wall time. We use Linux's timer_create() with CLOCK_THREAD_CPUTIME_ID to set a timer that delivers a signal when a CPU time threshold is reached. The signal handler immediately terminates execution of JavaScript using V8's TerminateExecution() (which only terminates the specific isolate).
It sounds like your experience is from a system where each guest runs in their own process. Cloudflare Workers runs many guest isolates in a single process, therefore we cannot simply kill the process when one guest misbehaves. So, we have to do everything very differently from what a container host would do.
The line you quoted from the docs is about billing. The enforcement of limits, and the calculation of billing, are completely unrelated.
Here are some reference links if you want to understand more about how our platform is implemented:
> "Cloudflare Workers runs many guest isolates in a single process, therefore we cannot simply kill the process when one guest misbehaves. So, we have to do everything very differently from what a container host would do."
Does this imply that another guest Worker can impact/takedown my Worker due to their tasks misbehaving?
> Does this imply that another guest Worker can impact/takedown my Worker due to their tasks misbehaving?
No, the system is designed to prevent that. Each guest runs in its own V8 isolate which we carefully control to prevent interference.
(Of course, all software has bugs from time to time. But we consider it a security flaw if one worker can somehow disrupt other workers, and handle it accordingly.)
Of course! Many people are deploying full-blown web apps on Workers today. We're constantly working on new features to fill in gaps so more types of apps can be built entirely on Workers. Durable Objects, cron triggers, increasing the time limit from 50ms to 30 seconds (and eventually 15 minutes), etc. are all part of this, and we have more coming.
That could be the case. I ran in to this trying to rescale PNGs in pure JS and hit CPU time limits immediately with lots of wall-clock time to spare. In practice it doesn't matter too much if the CPU limit kills the task or not, we're talking 50ms at most.
Isolated VM is a decent way to use lower level v8, but replicating "fetch" and the other CF workers primitives is a big chunk of work: https://github.com/laverdet/isolated-vm
vm2 does what you're looking for IIRC. Do a dynamic import check with an optionalDependency and write some glue over vm2 with a fallback to the built-in.
Basically your dev environment runs in the cloud on Cloudflare, then opens a mini browser - within your browser - (with it's own dev tools) for you to send HTTP requests to the dev environment.
Have you used `wrangler dev`[1], their CLI-based workflow? I don’t need to use the web editor at all - I use my preferred editor and use wrangler to trigger builds + `wrangler tail` to get a stream of logs.
The linked project (miniflare) is effectively an local emulator, but Cloudflare does provide a solid “hybrid” local-remote workflow, even if not perfect.
its a welcome addition to the cf worker ecosystem especially because of the features that are missing in most alternatives. however deno would lend itself much better to running cf workers locally and also i feel after the 4th cf workers testing environment it would be time to focus not on "simulation" or local testing but to start projects with the goal of being a compatible production ready implementation. such a project could be used for local testing and also for creating cf worker compatible services like deno deploy or just a compatible docker container that runs in your datacenter as an alternative to a nodejs express server, the possibilities are endless.
cf workers and deno both have a philosophy of web apis first where custom apis are mostly a last resort if the concept to be done does not exist in web apps or is out of scope. nodejs requires wrapper libraries like node-fetch etc. also deno and cf workers have both the idea to not share any access to host environments or siblings with js code and both use isolates to do this similar to chrome. nodejs usually shares the rights of the executing user.
I'd love a service where I can push my {INSERT_YOUR_FAVORITE_WEBAPP_FRAMEWORK} to the edge and not have to manage the OS and Database. Is that what fly.io is building?
I use it to personalize content that should be in a CDN cache but can't because it's personalized.
I have application configurations that need to load super fast as they block application rendering. The magic of the configuration is they can be modified by rules based on the user loading the app, so I pull the configuration out of Cloudflare KV Store, tweak it a bit for the user, and return it.
- Mature CLI tool, easy to build into CI and/or API with JSON responses
- Docker based, so I can easily test my apps locally
- Well designed secrets management
- Well designed private networking if I need to log into running apps in any region
There are probably more, but those are the big ones I see from using Fly regularly
> I prefer https://fly.io - their dev experience is 10x better.
I really like Fly, but it’s not a straight comparison - Fly is a way to run OCI (“Docker”) images in a handful of locations across the world, with some helpful magicks to route users to the closest instance (provided you run them). Thus, the dev experience is… you’re building and running a container locally, just as you would in Cloud Run, Heroku or other services that run containers for you. That familiarity is nice (and certainly an intentional choice by Fly) but it’s hard to say it’s “theirs”.
Workers runs everywhere, simultaneously: all 200+ of their edge locations. They’re designed to be lightweight enough and don’t need “you” to scale them, or pick regions to deploy them into, but the trade-off is that the API & development workflow are more bespoke (a JS-based Service Worker like API). If I want to deploy something that can be as close to end-users as possible, or that can personalize responses from my origin or cache on-the-fly, I reach to Workers first.
Is there any support for emulating the CPU runtime limitations that Cloudflare imposes (10ms or 50ms for paid plans)?