Singleton Services and the Idea of Caching
In this lesson, we'll learn about singleton services and how to use them as a store to hold temporary information throughout our server's life by building a simple in-memory caching service.
- Author
- Tom Gobich
- Published
- Jan 31
- Duration
- 6m 11s
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
Singleton Services and the Idea of Caching
-
[MUSIC]
-
So currently, any time that a user makes a request to our homepage or
-
an individual movie page, we're finding the file for the movie, reading it,
-
parsing it, and then sending it back to the user.
-
Whenever we can streamline that process a little bit by using something called
-
caching, which essentially allows us to store that information in memory, so
-
that we can skip all the processes in between.
-
To start with, let's go ahead and create a new service.
-
So we can right-click our services folder, new file, and
-
let's call this CacheService.
-
Within here, we'll create a new class called CacheService, and
-
we'll have a private variable called Store.
-
We'll set this variable's type to record string any, and set it to an empty object.
-
We're gonna have a couple of methods that will allow us to perform CRUD
-
operations against our store.
-
So CRUD meaning create, read, update, and delete.
-
But first, let's have a method that will allow us to determine whether or
-
not something already exists in the store.
-
We'll call this has, provide in a key of type string, and
-
we'll return back key in this.
-
So we're just gonna return back is key in this store.
-
If it is, we'll have true, otherwise it'll be false.
-
Next, let's focus on get.
-
So let's allow us to get something out of our store.
-
So get key string, return this.store, and let's reach for an individual key.
-
Then we'll have set, specify the key that we wanna set into, the value.
-
And then this store, set it on the key, equals value.
-
Scroll down just a little bit here.
-
And then lastly, we wanna be able to delete.
-
This will be a key string, and let's just delete this store key.
-
So we'll just delete the key straight out of the object.
-
So now this service is going to serve as our in-memory cache.
-
Everything for it will be stored within the store variable, and
-
then we'll have the methods to be able to perform CRUD operations against the store.
-
So in order for us to actually hold information within our cache service
-
store, we're gonna need to hold it in memory.
-
Meaning we're gonna need to create this cache service as a singleton,
-
which means that we're gonna need a single instance of this cache service to live
-
throughout the lifespan of our server.
-
Now this is quite a mouthful and it might sound hard to understand, but
-
really all that we need to do is at the bottom of our file,
-
instantiate a new instance.
-
So let's do const cache = new cache service.
-
And then we just need to export this single instance out of this file.
-
So export default cache.
-
Now the reason I'm not just doing export default new cache here,
-
is so that we're actually giving this variable a name.
-
Which is going to aid in our ability to import this file throughout our codebase.
-
So now the reason that this will actually allow this cache service to serve as
-
a singleton is because whenever we first import this file into our codebase,
-
it will instantiate the new instance of our class and kick that back.
-
Any other imports therein will use this same instance of our cache and
-
return that back whenever we attempt to import this file.
-
Meaning we can use this cache service in our movie model, movie controller, so on
-
and so forth, and we'll be referencing the exact same store that we have
-
within this one instance, making it a singleton.
-
So let's give this a save and try this out.
-
So let's jump into our movie model.
-
And anytime that we find the movie, let's go ahead and store it into our cache.
-
So after we finish creating the movie and setting all of its data,
-
let's do cache, which is the variable that we've called the instance.
-
And you'll see that Visual Studio Code will pick that up and
-
allow us to just hit Tab to auto import it, nice and easy.
-
Then we'll wanna use the set method that we created.
-
We'll set it on the slug, so we'll use the slug as the key.
-
And for the value, we'll set it to movie as a whole.
-
At the top of this find method now, we can check to see whether or
-
not the movie that we're trying to get already exists within our cache.
-
And if it does, we can bypass all of this and just return the cached version.
-
So let's do if cache.has the slug that we're trying to find.
-
Then we just wanna return cache.get and then provide in the slug so
-
that we can get the underlying movie stored for the slug within our cache.
-
Let's also add a console.log in here so
-
that we can determine whether or not something's being hit by the cache.
-
So let's console.log and let's do cache, hit, and provide in the slug value.
-
We can give this a save.
-
And we're already making use of our find method within our controller.
-
It's being used for both the all method and the find method.
-
But to show you that the cache is going to allow us to access the store from
-
anywhere within our code base now, let's go ahead and
-
comment out the movie that we have right here.
-
And let's do const movie equals cache.
-
Let's import that, .get, and let's pass in params.slug.
-
So now in order for this to work, we'll need to hit our home page so
-
that all of our movies get cached.
-
And then whenever we try to find an individual page,
-
it will use that same store used within our movie model to cache
-
all of our individual movies to then fetch our movie from the cache
-
that's stored in memory.
-
So let's give that a try.
-
Let's save this file, open up our browser.
-
We need to hit our home page first.
-
Okay, we can inspect our terminal and
-
notice that we don't have any console.log stating that our cache was hit.
-
If we now refresh the page, view our terminal once more, cool.
-
Our cache was hit for each of the three movies that we have.
-
Let's try to now dive into one of our movies and look at that.
-
We were able to get the information A-OK,
-
despite our code not actually reading the movie directly from the file.
-
Instead, it's reading it from our in-memory cache.
-
That's pretty cool.
-
We can go home.
-
Let's try another one and let's try the third.
-
All three are working A-OK.
-
If we were to restart our server at any point in time, so
-
let's stop our server and start it up again.
-
We now see that we get an error within our browser,
-
cannot read properties of undefined reading title.
-
And that's because we no longer have an in-memory reference of our underlying
-
movie because whenever we stopped our server, the singleton was destroyed.
-
And then recreated again whenever we booted our server back up,
-
clearing out that in-memory store.
-
And that's why we don't want to read just straight from the cache, but
-
we want to instead first try to determine whether or not the cache holds something.
-
And then if it does, we can read directly from the cache.
-
Otherwise, we want to have a fallback mechanism to get a fresh instance
-
of the object.
-
So let's jump back into our movies controller and
-
set this back to how it was, just like so.
-
Give this a save, we can get rid of our cache import here.
-
And we can get rid of these other imports that we're no longer using.
-
Save once more, jump back into our browser, give this a refresh, and
-
we see our movie once more.
-
If we check out our terminal, that time it did not hit the cache.
-
But if we refresh the page, view our terminal once more,
-
we have a cache hit for this one instance of our movie.
-
If we hit back to our homepage, the other two movies are now cached.
-
And this homepage read from the cache for the third movie that we already had cached.
-
Now all three movies exist within our cache.
-
So if we attempt to dive into any one of our other movies,
-
it will now read from the cache.
-
So here we can see cache was hit for Awesome Movie of the Trilogy.
-
[BLANK_AUDIO]
-
Introduction
-
Fundamentals
-
2.0Routes and How To Create Them5m 23s
-
2.1Rendering a View for a Route6m 29s
-
2.2Linking Between Routes7m 51s
-
2.3Loading A Movie Using Route Parameters9m 17s
-
2.4Validating Route Parameters6m 6s
-
2.5Vite and Our Assets6m 38s
-
2.6Setting Up Tailwind CSS9m 5s
-
2.7Reading and Supporting Markdown Content4m 32s
-
2.8Listing Movies from their Markdown Files8m 51s
-
2.9Extracting Reusable Code with Services7m 4s
-
2.10Cleaning Up Routes with Controllers4m 52s
-
2.11Defining A Structure for our Movie using Models9m 38s
-
2.12Singleton Services and the Idea of Caching6m 11s
-
2.13Environment Variables and their Validation4m 16s
-
2.14Improved Caching with Redis10m 44s
-
2.15Deleting Items and Flushing our Redis Cache6m 46s
-
2.16Quick Start Apps with Custom Starter Kits6m 28s
-
2.17Easy Imports with NodeJS Subpath Imports8m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating Basics8m 49s
-
3.1HTML Attribute and Class Utilities6m 9s
-
3.2Making A Reusable Movie Card Component10m 24s
-
3.3Component Tags, State, and Props4m 53s
-
3.4Use Slots To Make A Button Component6m 56s
-
3.5Extracting A Layout Component5m 13s
-
3.6State vs Share Data Flow2m 59s
-
3.7Share vs Global Data Flow6m 7s
-
3.8Form Basics and CSRF Protection6m 13s
-
3.9HTTP Method Spoofing HTML Forms3m 3s
-
3.10Easy SVG Icons with Edge Iconify7m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database Connection4m 3s
-
4.1Understanding our Database Schema9m 35s
-
4.2Introducing and Defining Database Migrations18m 35s
-
4.3The Flow of Migrations8m 28s
-
4.4Introducing Lucid Models5m 43s
-
4.5Defining Our Models6m 49s
-
4.6The Basics of CRUD11m 56s
-
4.7Defining Required Data with Seeders11m 11s
-
4.8Stubbing Fake Data with Model Factories13m 48s
-
4.9Querying Our Movies with the Query Builder15m 30s
-
4.10Unmapped and Computed Model Properties3m 24s
-
4.11Altering Tables with Migrations7m 6s
-
4.12Adding A Profile Model, Migration, Factory, and Controller2m 57s
-
4.13SQL Parameters and Injection Protection9m 19s
-
4.14Reusable Query Statements with Model Query Scopes8m 11s
-
4.15Tapping into Model Factory States9m 15s
-
4.16Querying Recently Released and Coming Soon Movies4m 59s
-
4.17Generating A Unique Movie Slug With Model Hooks7m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid Models5m 49s
-
5.1Model Factory Relationships2m 54s
-
5.2Querying Relationships and Eager Vs Lazy Loading5m 17s
-
5.3Cascading and Deleting Model Relationships5m 16s
-
5.4Defining One to Many Relationships with Lucid Models6m 56s
-
5.5Seeding Movies with One to Many Model Factory Relationships5m 24s
-
5.6Listing A Director's Movies with Relationship Existence Queries8m 41s
-
5.7Listing and Counting a Writer's Movies8m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and Director5m 18s
-
5.9Defining Many-To-Many Relationships and Pivot Columns9m 48s
-
5.10Many-To-Many Model Factory Relationships4m 50s
-
5.11A Deep Dive Into Relationship CRUD with Models18m 5s
-
5.12How To Create Factory Relationships from a Pool of Data13m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table Data9m 47s
-
-
Working With Forms
-
6.0Accepting Form Data12m 15s
-
6.1Validating Form Data with VineJS9m 29s
-
6.2Displaying Validation Errors and Validating from our Request7m 16s
-
6.3Reusing Old Form Values After A Validation Error2m 3s
-
6.4Creating An EdgeJS Form Input Component5m 28s
-
6.5Creating A Login Form and Validator5m 1s
-
6.6How To Create A Custom VineJS Validation Rule9m 7s
-
-
Authentication & Middleware
-
The Flow of Middleware7m 49s
-
Authenticating A Newly Registered User4m 14s
-
Checking For and Populating an Authenticated User2m 10s
-
Logging Out An Authenticated User2m 24s
-
Logging In An Existing User6m 54s
-
Remembering A User's Authenticated Session6m 55s
-
Protecting Routes with Auth, Guest, and Admin Middleware5m 36s
-
-
Filtering and Paginating Queries
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!