Playing Next Lesson In
seconds

Transcript

  1. So when we left off, we had our Redis cache working A-OK. Our data was getting stored in the Redis. We were able to read it back out, list it on our page, view the details of a single movie.

  2. Everything was just working. Now, I've gone into the Redis cache and manually altered the data so that it would be invalid. So if I give the page a refresh here, we'll see unexpected token S,

  3. and it's trying to read some bad, and I have data right here. It's not valid JSON whenever we try to parse out the JSON in our get method. You can see if we dive through the show frames here,

  4. if we click on cache service, the error is happening right here within our get method where we're trying to parse the value out. We're finding a value. Our hazard is returning back that we have some sort of value

  5. because the database itself has a value. So we're getting to the JSON parse OK, but the parse is failing because it's not valid JSON for it to actually parse out.

  6. So as we try to refresh our server and refresh, it's still just going to run into the same issue since it's just reading from our cache over and over again, but our cache holds the invalid data.

  7. So what we need to do is clear our cache out. So let's hide our browser back away, and let's give ourselves a way to clear our cache out.

  8. With our old singleton service that held everything in memory within that singleton, all that we had to do was stop our server and restart it, but Redis is running on a completely different server,

  9. so we need to actually provide our application a way to clear it out. So we'll define a new route within our routes, and we'll call this router.delete, and we'll set this to /redis,

  10. and then we'll have a particular slug that we can provide to delete it out. Let's also create ourselves a controller to house this route. So let's hide our text editor back away, stop our server, clear it out,

  11. and let's do node ace, and there's a command called make controller, and we can provide a name for this controller. So we'll call ours Redis.

  12. So now we have a new controller called Redis controller within our app controllers directory. Let's go back into our text editor, and now we can define that controller. So we'll do Redis controller, tab to auto import,

  13. and let's define some methods on that controller. So let's dive into our Redis controller. Let's uncomment the HTTP context import, and let's do public async,

  14. and we'll call one method destroy. For this, we'll extract out our response, set the type to HTTP context, and now we're ready to do the route handler. I'm going to go ahead and copy this, paste it in,

  15. and let's create another method called flush. So within our destroy method, we will destroy a singular key. Within our flush method, we will flush our database for Redis.

  16. So we want to interact with our cache service, so we can do await cache and hit tab to auto import that, and we can call delete and pass in the key that we're getting from our params.

  17. So let's also extract our params out of our HTTP context, and we can do params.slug. Then we can just return the user back to where the call came from.

  18. So for that, we can return, we can utilize the response object to redirect the user, and off of the redirect method, we can chain an additional method called back

  19. that will actually read from the referrer header and send the user back to what referred them to this particular destroy handler. Getting tired of the red squiggly, so I'm going to go ahead and hit save

  20. so that the indentation happens. Ah, I didn't like my public declaration there. Okay. Within our flush method, we'll want to do something very similar, except instead of calling delete with a particular slug,

  21. we'll just call flush database. So we'll wait, cache., we have our flush DB method. It doesn't take anything in, so we're good there.

  22. Now we'll just return response redirect. Give that a save, and now we need to define routes for these.

  23. So we'll dive back into our routes.ts, and we'll call destroy for this one. As redis.destroy, we can copy this declaration, and instead of slug, this will be flush,

  24. and instead of destroy, this will be flush, and for the name, it too will be flush. Now here we've just come across something to learn.

  25. Adonis, whenever it's searching for a route to match our request, is going to use the first request that it finds matching for the route.

  26. Flush is a valid slug, meaning that if we attempted to call redis/flush, Adonis will never actually utilize this particular route definition

  27. because it matches this one, and this one's defined first. Since it stops the first match for the request, our redis flush will always use this route handler.

  28. So since we want redis flush to specifically use this route handler, we're going to want to put it first. With it being first, if the request is specifically for redis/flush,

  29. this route handler will get used. If it's any other type of slug, this route handler will get used. So ordering does matter whenever you're defining your routes,

  30. whether that be a delete, get, post, put, patch, or whatever. And now we need a way to call these delete methods. Now at this point, if we were to try to send these delete requests out,

  31. that would get into a couple of things that we're not quite ready to talk about yet. So although we would definitely want these to be something like a delete request, let's switch these to a get request for right now.

  32. Give these a save, and now all we have to do is send out a request to our browser, and they'll work A-OK. We'll switch these back to delete requests before we end this lesson now so that they're correct. So let's jump back into our browser.

  33. We need to restart our server, so let's go ahead and dive back into our terminal. npm run dev there. OK. Let's first verify that we still have our issue. Yep, sure do.

  34. So let's open up another tab, and let's go to localhost 3333/, and we made our URL for flushing a single key, redis/,

  35. and then whatever that slug is. Well, the one that I intentionally sabotaged was awesomemoviethetrilogy. So if we hit Enter here, this request will match our redis delete route,

  36. and it will delete out the specific individual key for awesomemoviethetrilogy, and it should clear out our error. So let's go ahead and hit Enter here, and voila,

  37. we got redirected right back to the home page after it cleared out that key. If we jump back into this page where we had the error, give it a refresh, everything's still working A-OK.

  38. If we refresh again to make sure that we're reading from our cache, everything is still working. So we get rid of our extra tab now, jump back into our terminal, and indeed we can see everything's coming from the cache.

  39. Let's do this one more time. I'm going to clear our terminal out by restarting our server to give us a clean cache hit slate. OK, let's go ahead and flush our database now.

  40. So let's dive back into here. We'll go to /redis/flush, which should clear out all of the caches that we have stored so far, which would just be our three movies.

  41. So let's go ahead and hit Enter, and we got redirected back to the home page. Since we had just booted up our server and we had just cleared our cache, these three here should not have hit our cache at all.

  42. So if we dive back into our terminal, sure enough, no cache hits. If we give the page a refresh, jump back into our terminal, there's our cache hits once more. So now we know how to delete an individual cache item

  43. or the entire cache database if we were to run into any issues. Let's hide this away, jump back into our text editor, and switch these back to deletes as they're supposed to be.

  44. Whenever we get into talking about forms, we'll break these up to actual forms so that we can utilize them.

Deleting Items and Flushing our Redis Cache

@tomgobich
Published by
@tomgobich
In This Lesson

Not everyone is perfect, and one day you'll accidentally cache bad data and need a way to quickly clear it out. In this lesson, we'll learn how we can create two routes to clear a single Redis key or flush the entire database.

Join the Discussion 4 comments

Create a free account to join in on the discussion
  1. @codthing

    After testing with these two route methods, there were no changes in the Redis database. The three movie records still remain—they haven't been destroyed or deleted.

    //routes.ts
    router.get('/redis/flush', [RedisController, 'flush']).as('redis.flush')
    router.get('/redis/:slug', [RedisController, 'destroy']).as('redis.destroy')
    Copied!

    1
    1. Responding to codthing
      @codthing
      //redis controller
      export default class RedisController {
          public async destroy({ response, params }: HttpContext) {
              await cache.delete(params.slug)
              return response.redirect().back()
          }
      
          public async flush({ response }: HttpContext) {
              await cache.flushDb()
              return response.redirect().back()
          }
      }
      Copied!
      1
    2. Responding to codthing
      @codthing
      //cache service
      export class CacheService {
        async has(...keys: string[]) {
          return redis.exists(keys)
        }
        async get(key: string) {
          const value = await redis.get(key)
          return value && JSON.parse(value)
        }
        async set(key: string, value: any) {
          return redis.set(key, JSON.stringify(value))
        }
        async delete(...keys: string[]) {
          return redis.del(keys)
        }
        async flushDb() {
          return redis.flushdb()
        }
      }
      const cache = new CacheService()
      export default cache
      Copied!
      1
    3. Responding to codthing
      @tomgobich

      Hi codthing! Everything you've shared looks right. If you're viewing your Redis database with a GUI application, those often don't reflect live data and require refreshing in order for them to reflect changes made to the database contents. Also, make sure you're viewing the Redis database actually being used by your application! This can be found within config/redis.ts

      const redisConfig = defineConfig({
        connection: 'main',
      
        connections: {
          main: {
            host: env.get('REDIS_HOST'),
            port: env.get('REDIS_PORT'),
            password: env.get('REDIS_PASSWORD', ''),
            db: 1, // 👈 indicates I'm using Redis DB1, DB0 is typically the default
            keyPrefix: '',
            retryStrategy(times) {
              return times > 10 ? null : times * 50
            },
          },
        },
      })
      Copied!
      • config
      • redis.ts

      You might also do a sanity check, just to ensure your controller methods are actually being hit correctly, by adding a console log to each.

      //redis controller
      export default class RedisController {
          public async destroy({ response, params }: HttpContext) {
              console.log('destroy', params.slug)
              await cache.delete(params.slug)
              return response.redirect().back()
          }
      
          public async flush({ response }: HttpContext) {
              console.log('flushing redis')
              await cache.flushDb()
              return response.redirect().back()
          }
      }
      Copied!

      If neither of those help, please feel free to share a link to your repository and I can take a deeper look to see if anything stands out!

      0