ravendb / ravendb-nodejs-client

RavenDB node.js client
MIT License
63 stars 32 forks source link

V6: When updating the Cloudflare template, show RPC usage #458

Open ngbrown opened 2 weeks ago

ngbrown commented 2 weeks ago

With Cloudflare, it is common to deploy the web application via Cloudflare Pages so that static resources aren't part of the worker's code size limit. But ravendb-nodejs-client can't live in a Pages function so it has to be deployed to a separate Cloudflare service workers instance.

The reason RavenDB can't be deployed to Cloudflare Pages is because Pages functions doesn't currently have the ability to bind to a mTLS certificate.

The size of the RavenDB library would also encroach on the 1MiB code size limit for a Pages function. A service worker with just the RavenDB client and almost nothing else deploys with a size of 1,044 KiB / gzip: 191 KiB.

I think I've seen Cloudflare advocate for splitting the application between workers along the layers of an application. (I can't find a reference for this right now, but it might have been in their Discord channel, for example). A approach would be to then use RPC service bindings between the two parts of the application. With an RPC binding, the two parts actually run together in the same isolate (and thread) on the server.

When using RavenDB with RPC bindings, returning a RavenDB entity as is causes an exception because the @metadata can't be structured cloned. So in my application, I have to "pre-clone" the entities and strip the @metadata field before returning it from the RPC method.

Another change I made from the RavenDB documentation is store the documentStore at the module level so it doesn't get re-initialized on every function call or request. Even though the workers aren't long-lived, this helped reduce the number of new connection being made per-second and eliminated a warning that was being raised in the RavenDB console.

I think that the RavenDB Cloudflare template should cover these concerns, so that's why I'm bringing it up. It would be a little more complicated than just using a single worker as there would be two projects, one pages functions and one service worker, or two service workers. This would be fairly approachable with npm workspaces.

ayende commented 2 weeks ago

Can you give some more context on what you suggest? Is there a need to make changes to the client to support it? Or are we talking about guidance docs?

ngbrown commented 2 weeks ago

When trying to deploy an application to Cloudflare Pages, I got the RavenDB client working with my application so no change in the client is strictly necessary. Like I outlined above, I had to setup a separate Workers application with RPC service bindings and then strip the @metadata field (because it's a class) from returned objects.

So this could be just an updated template (https://github.com/ravendb/template-cloudflare-worker) and documentation guidance. Including how to properly avoid the too many connections warning when Cloudflare passes the components of the DocumentStore constructor separately on each request.

Or during the process of setting up a Cloudflare pages application, you'll find other changes you would like to make to the client library. I would like to know if using a class for the @metadata object is strictly necessary, or is there something that can be done to make the client-fetched entities compatible with Cloudflare's variation of structured clone (throws on classes).

ayende commented 2 weeks ago

For the class vs object - I'll let @ml054 answer

For the rest - given that you are currently going through that, you are likely our best source of information. Would you be able to post your notes on what is required here?

We are trying to get more technical articles on RavenDB and would love to publish this here: https://ravendb.net/posts