Developers August 6, 2020

Just finished an MVP for handling client side caching and looking for some Beta Testers

Avi Prince @Dukko18

Hi Devs,

I've been doing full stack web development for the past 8 years or so and one issue I kept running into over and over again is client side caching. Modern browsers have some amazing built-in tools for caching websites, but more often than not, we are forced to apply cache-busting techniques to ensure that our users will always get the latest code changes when we deploy and we miss out on all of the benefits of browser caching as a result.

I just finished building an MVP called JellySync (beta.jellysync.com) that will let developers get the best of both worlds. You simply login to our dashboard, create a project, and add the script tag to the header of your html. With the package installed, your active sites will keep an open connection to our server and with the click of a button in our dashboard you will be able to update all of your users (both live and future) to the latest version at anytime. You can also configure what your site does when it receives an update such as clearing local storage, session storage, cookies, cache, or forcing a mandatory refresh. What this means is that you can leave on client side caching and still be confident that your users will always be updated when you want them to be.

Right now we are looking for beta testers to make sure it works in the real world and get real feedback on whether or not it is something people find useful. If you are interested in giving it a shot, head on over to beta.jellysync.com and submit your email. We'll create an account for you and make sure you get setup without any issues.

I wanted to share 2 recent experiences I had that really pushed me to make this tool. The first is what you would expect. Our team was implementing a web app and we were applying cache busting to make sure users always got the latest code when they came to the site. But, for some reason, the index.html file was being cached by the browser and would cause the app to crash as soon as it was loaded until the user did a refresh. We ended up fixing the problem, but we wasted a bunch of dev hours and we received many complaints about "white screens" for a few days which wasn't great for encouraging users.

The second experience was a bit more scary. We had just deployed a brand new feature to our app. Unfortunately, we didn't realize that it caused a memory leak and was downloading videos in a loop. This was eating up our bandwidth incredibly quickly and was going to cost us real money if we didn't fix the problem immediately. The problem though was that we had no way to force all of our users to update to the latest version gracefully. Just because we updated the client doesn't mean that there weren't users on the previous broken version. The only thing we could do was to take down the site temporarily so that everyone would get the fix when we started it back up.

Both of the above stories would never have been a problem with JellySync. All I would have had to do was click a button and my users would have been gracefully forced into the latest version.

So, this post turned out to be much longer than I initially anticipated. If you made it to the end, thanks so much for reading! I hope that I have piqued your interest a bit and you will come and give JellySync (beta.jellysync.com) a try. I look forward to all of your feedback!

  1. 2

    Thanks for sharing! some questions/feedback:

    When you say this:

    your active sites will keep an open connection to our server

    does that mean the browser is keeping an open websocket connection to your server or is it polling for an update?

    In the case of a websocket, how do you plan to scale that for websites that have thousands or more of concurrent users? What would be the cost to the site owner to subscribe to your service?

    In the case of polling, what does your service offer me as a developer that I cant get by simply writing a version string to an un-cached file in S3 and then polling it from my client side code? Assuming that my source files are versioned already through a URL pathname or query parameter, all I need to do is reload the page if a difference is detected to load in the new version served up by my server.

    You can also configure what your site does when it receives an update such as clearing local storage, session storage, cookies, cache, or forcing a mandatory refresh

    How would this work for cookies that are HTTP only and thus not accessible to client-side javascript?

    and with the click of a button in our dashboard you will be able to update all of your users (both live and future) to the latest version at anytime

    Can this be triggered programmatically as part of my CI/CD build process?

    You can also configure what your site does when it receives an update such as clearing local storage, session storage, cookies, cache, or forcing a mandatory refresh

    How is this configured? Through the UI or is there a client-side SDK that I can integrate with that provides hooks for various update stages? e.g. "updatePresent", "preUpdate", "postUpdate", etc just to throw out some potential examples.

    Id also love to learn more about this use case:

    Let's say you store your authentication information in cookies or localstorage. Then a day comes around and you find you need to make an update to your authentication flow. You deploy updates to your server and client, but you need your users to clear their old authentication tokens and login fresh.

    Typically the way Ive rolled out a change like this is to change the key I use to sign my JWTs. This means that any JWT that was signed with the old key will show up as invalid on page load and the session implicitly expired sending the user back to a login page. Id love to hear about some more use-cases that are solved by jellysync for this authentication example.

    1. 1

      Hi! Thanks for asking such great questions. I'll do my best to go through them.

      does that mean the browser is keeping an open websocket connection to your server or is it polling for an update?

      When I say "open a connection" I mean websockets. I wouldn't add polling to a website, that just seems cruel. We are using Firebase's Realtime Database for our websockets and they have fantastic scaling. As for the cost, we are still working out the details. We plan on having pricing options based on the number of connections your site needs, but we don't have a clear picture of what those numbers are or what the proper price would be. Part of getting beta users is finalizing these numbers.

      How would this work for cookies that are HTTP only and thus not accessible to client-side javascript?

      We can only clear what is accessible from the client which unfortunately means we cannot access HTTP-only cookies. They will have to be cleared from the server.

      Can this be triggered programmatically as part of my CI/CD build process?

      Yes! We haven't finalized it yet, but we absolutely plan on supporting CI/CD and hope to make that a large part of the product offering. Automating the process is the goal! I will keep you posted as to when it is fully ready.

      How is this configured? Through the UI or is there a client-side SDK that I can integrate with that provides hooks for various update stages? e.g. "updatePresent", "preUpdate", "postUpdate", etc just to throw out some potential examples.

      Right now, you configure everything through our dashboard. We have a pretty simple/straightforward interface for what happens during an update. It's not accessible via API yet, but it's part of the eventual roadmap.

      Having update stages sounds like a really cool idea, but I'm not really sure what the exact use case would be? I would love to hear more of your thoughts!

      Typically the way Ive rolled out a change like this is to change the key I use to sign my JWTs. This means that any JWT that was signed with the old key will show up as invalid on page load and the session implicitly expired sending the user back to a login page. Id love to hear about some more use-cases that are solved by jellysync for this authentication example.

      That makes sense. I've honestly never done it that way myself, but it's actually a really simple way to logout your users. JellySync would end up having the same result because the token would be cleared from the client instead of being invalidated. The advantage though is that you don't have to change your JWT secret key on every release. We also have the extra benefit of being able to force your users to refresh so you don't have to wait until a new API request is made for them to get logged out.

      The real use case isn't really limited to authentication but is based around being able to remotely clear client cache. For example, if you have updated your privacy policy and want your users to review them. You can clear any localstorage/cookies you have stored in the client saying that they've already looked at the privacy policy instead of coding up new ones to check.

      Hopefully, I've answered all of your questions so far? But, if you have more please ask away!

    2. 2

      This comment was deleted 5 months ago.

      1. 1

        Yes! It is definitely part of our plan to be integrated into CI/CD workflows. It is a really important part of our vision of the product. It makes me happy to hear that it is a feature that developers will consider important.

        I will keep everyone posted as soon as I finish implementing it.

    1. 2

      That's because we are no longer in beta and are using jellysync.com 😄

        1. 2

          We did for a month or so and then we weren't getting any traffic to it so we took it down.

  2. 1

    I totally get the value proposition, specially with service worker, without implementing a popup "Hey there is a new release, click refresh" it is sometimes/often hard to spread update to all clients.

    Kind of an Ionic Appflow but for PWA.

    Speaking of Ionic, you might want to update your favicon 😉

    Are you planing to open source your solution?

    1. 1

      I'm glad you like the idea! Yeah we have a popup you can customize that will appear for the users before it auto refreshes. Nice and clean warning for them that they are about to get updated.

      Speaking of Ionic, you might want to update your favicon 😉

      Haha yeah! We are almost done with our logo and we will update our favicon as soon as it's ready.

      Are you planing to open source your solution?

      The npm package is open source. We don't want to have anyone install anything on their site that they aren't comfortable with. You can check it out here: https://github.com/Jellysync/jellysync

      1. 1

        Really cool that you open sourced the client 👍👍👍

        Now that I had a quick look at these sources I do understand your concept better.

        Do I understand correctly, in your concept, this "jellysync" lib would have to be added and use in frontend applications, is that correct?

        1. 1

          Yes, you install the jellysync package in your index.html head tag. Then when you update the version of your project on our server (either through our dashboard or our API) you will trigger all of your active users to update to that version live!

          The goal is to make it easier to handle your client side browser caching 😊

          1. 1

            Thank you.

            Don't know if it is the final form and concept of your jellysync package or not, but if it would be, I noticed a couple of things which, at least to my point of view, would probably be for me a reason to not use your service if I had too.

            Indeed you are using jquery, axios and firebase as dependency for your library which, per extension, would have to be added to the bundles of the apps using your service. Therefore, each apps using your client are going to perform slower at boot time.

            Moreover, don't know if you gave it a try, but spontaneously I would say that I am not sure it would be compatible with any other apps using Firebase too? Can an app register two Firebase configurations? I never try but isn't initializeApp.initializeApp(firebaseConfig); global?

            Spreading your Firebase config tokens, even if public, in all the apps which are going to use the client might also be a problem at some point in the future, like if your tokens expire and change?

            That's why, I would suggest to not use jquery (in any case), use the native fetch api instead of axios and replace Firestore in your package with for examples Api calls or else.

            Just sharing these remarks in case it helps and again, if I understood correctly the code and concept. If not, forget everything I just said 😅.

            1. 1

              Wow what great feedback! Thanks I really appreciate it. All your points are fantastic and I will be updating the package to address all of them. I'll keep you posted as soon as I finish!

              1. 1

                Awesome, really super happy to hear it was useful!

                For sure, keep me posted, ping me on twitter.

  3. 1

    This is an interesting use case. We're running into this issue even though we use AWS Cloudfront and clear our cache in cloudfront on every new deploy, it doesn't guarantee that every client is seeing the latest version. We've had to literally email our beta users asking them to log out and log back in to see the new version. Even after logging out, they would still sometimes need to refresh the login page to really get the latest version of the single page app in JS that we've built which is deployed via cloudfront. It's been an issue for sure. We're created some workaround where we're able to remotely log them out but forcing them to refresh their page or clear their cookies and localstorage has been pain. So i'm curious about your solution. I can't go ahead and deploy this right away as we have real customers using this but I'll be watching this thread for more updates and get involved when I feel comfortable.

    Could you go into more technical details about how much more latency would this add to any existing site as well as your security protocols and uptime guarantees etc? I understand that you're doing this as beta for now so you may not be ready with all of this. We're in the same boat as well. I'd still just like to hear your product roadmap so I know where this product is headed.

    Hope that helps! Thanks again for creating something useful that actually solves a real pain point.

    1. 1

      Hi,

      To answer your immediate caching issue (nothing to do with JellySync):

      The first example I mentioned above is the exact scenario you are talking about. The index.html file was being cached so users were still trying to load old js files and it was crashing on load. We solved this by updating the cache headers on the html file directly during deployment to S3 with:

      --cache-control max-age=0,must-revalidate --content-type text/html

      That will hopefully solve your immediate problem.

      (Back to JellySync)
      Your story is exactly why I created JellySync! I am so tired of having to deal with these caching issues every single time I work with a new application. I just wanted a simple solution I know will work.

      Could you go into more technical details about how much more latency would this add to any existing site as well as your security protocols and uptime guarantees etc?

      We haven't seen any latency issues. All you are doing is downloading our npm package and having your site asynchronously open a websocket to our server. Everything else happens when the site is actually receiving update instructions from our server.

      We use Firebase for our backend and sockets and we follow their security rules to keep everything as secure as possible. We also don't transfer any important information such as PII, just a list of actions to follow. As for uptime, Firebase has some pretty good uptime guarantees (their SLA claims 99.95%) so you should feel pretty confident in that regard.

      I'd still just like to hear your product roadmap so I know where this product is headed.

      Right now we are focused on getting beta users and proving that there is a market need for this product. We also want to determine what the most important features are that are stopping users from signing up. Until then, our roadmap consists of lots of testing, finishing the API access for CI/CD use and improving the UX of our dashboard. Really, our main priority is proving it's worth investing more time into it.

      If you would like a demo I would be happy to give you one when you are ready! It sounds like it would be a great fit for your application.

      1. 1

        Thanks for the details @Dukko18. I'll look into this further and get back.

    2. 1

      Im curious here:

      We're running into this issue even though we use AWS Cloudfront and clear our cache in cloudfront on every new deploy, it doesn't guarantee that every client is seeing the latest version. We've had to literally email our beta users asking them to log out and log back in to see the new version. Even after logging out, they would still sometimes need to refresh the login page to really get the latest version of the single page app in JS that we've built which is deployed via cloudfront

      are you generating an index.html (or equivalent) that is being served by CloudFront that is maybe causing this problem? The reason I ask is because I haven't run into cache problems like this with a single page app written in React, but I also have some server side rendering so my "index.html" boilerplate isn't getting served up and cached by a CDN. If that is your case, you can disable caching for specified files by creating a "behavior" that should solve your issue. If you uncache your index.html file, but leave your other javascript, css, image, etc assets cached, you shouldn't run into any huge performance hits.

  4. 1

    Hey Avi - thanks for sharing. Can you explain how this differs from key based caching or improves upon it? Thank you!

    1. 1

      So, it's funny I never heard of key based caching before you asked so thanks for letting me learn something new!

      If I understand it correctly, key based caching is used primarily when requesting data from a server or api. You add a key to your requests so that you will always get the same data for a request with a specific key, but you know you can get fresh data as soon as you decide to use a new key instead.

      JellySync is not focused on cached data responses, it focuses on dealing with cached code. What JellySync does is ensure that the client side browser cache can be controlled/wiped remotely.

      Here's an example: You have a web app and its currently running v1 with a lot of active users. You now want to launch and deploy v2 of your app. It's especially important to deploy this because not only does it have great new features, it also has a bunch of bug fixes. So, how do you make sure that your users all get the update? Right now, you can't. You need to wait for them to eventually close the site and come back later. This gets even worse if you do have client side caching installed. Your users may not get the update for quite some time. With JellySync, you clear the user's cache and effectively push the update directly to the users in real time. No more waiting and no more worrying about supporting outdated versions.

      Here's another cool example: Let's say you store your authentication information in cookies or localstorage. Then a day comes around and you find you need to make an update to your authentication flow. You deploy updates to your server and client, but you need your users to clear their old authentication tokens and login fresh. You could do this with some complicated checks in your code, or you could use JellySync and wipe/clear your users cookies and localstorage remotely and automatically log them out. Clean and simple without any hassle.

      I hope this answers your question! Please let me know if I was completely off target. I'd be happy to clarify further if you need it.

Recommended Posts