Skip to content

BartekBanachowicz/tsd-cache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Redis Cache Tutorial

This repository contains a small Spring Boot tutorial for practicing key-value storage and Redis list operations.

Students complete the TODOs in the production code and use the tests to check each step. The tutorial is split into three tasks:

  • Task 1: implement an embedded in-memory storage for bad login attempts.
  • Task 2: implement the same storage with Redis and TTL.
  • Task 3: implement a Redis-backed FIFO task queue.

Prerequisites

Install and verify these tools before starting:

  • JDK 25.
  • Docker Desktop, Rancher Desktop, Colima, or another Docker daemon that is running and reachable from the terminal.
  • Internet access for the first Maven dependency download.

Check your environment:

java -version
javac -version
docker info

If Maven reports release version 25 not supported, your active java or javac is not JDK 25.

If tests report Could not find a valid Docker environment, Docker is not running or Testcontainers cannot reach it.

Running Tests

Run the full test suite:

Windows PowerShell:

.\mvnw.cmd test

macOS or Linux:

./mvnw test

Run one task at a time:

Windows PowerShell:

.\mvnw.cmd test "-Dtest=TaskNo1_1Test"
.\mvnw.cmd test "-Dtest=TaskNo1_2Test"
.\mvnw.cmd test "-Dtest=TaskNo2Test"
.\mvnw.cmd test "-Dtest=TaskNo3Test"

macOS or Linux:

./mvnw test -Dtest=TaskNo1_1Test
./mvnw test -Dtest=TaskNo1_2Test
./mvnw test -Dtest=TaskNo2Test
./mvnw test -Dtest=TaskNo3Test

Tasks 2 and 3 use Testcontainers to start Redis automatically, so Docker must be available even though you do not need to install Redis manually.

Task 1: Embedded Key-Value Storage for Bad Login Attempts

Goal

Implement in-memory key-value storage to track failed login attempts and integrate it with Authenticator.

The authenticator should:

  • Increase the counter after a bad password.
  • Lock a user out when the counter reaches the configured threshold.
  • Reset the counter after a successful login.

Part 1.1: Implement Authenticator

Complete these private methods in Authenticator:

  • increaseBadLoginAttemptsCounter(String email)
  • isLockedOut(String email)
  • resetCounter(String email)

Use the email address as the storage key.

Expected behavior:

  • increaseBadLoginAttemptsCounter calls badLoginAttemptsStorage.increment(email).
  • isLockedOut reads the counter and compares it with badLoginAttemptsThreshold.
  • resetCounter removes the email from storage.

Part 1.2: Implement EmbeddedBadLoginAttemptsStorage

This class should store counters in a HashMap.

Create this field:

private final Map<String, Integer> storage = new HashMap<>();

Then implement:

  • get(String key)
  • put(String key, Integer value)
  • increment(String key)
  • remove(String key)

Expected behavior:

  • Missing keys return 0.
  • put stores the provided value.
  • increment changes a missing key from 0 to 1.
  • increment adds 1 to an existing value.
  • remove deletes the key.

Run:

.\mvnw.cmd test "-Dtest=TaskNo1_1Test,TaskNo1_2Test"

Task 2: Redis Key-Value Storage for Bad Login Attempts

Goal

Implement Redis-backed storage for bad login attempts. Values should expire automatically after the configured TTL.

The class uses RedisTemplate and ValueOperations. The TTL is injected as a Duration, so do not hardcode seconds inside the storage class.

Redis connection details are provided by Spring Boot and Testcontainers during tests. Do not create your own JedisConnectionFactory; use the configured RedisTemplate that is already injected into the storage class.

The authentication Redis template is configured with serializers for you. Integer values use a serializer compatible with Redis INCR, so redisOperations.increment(redisKey) can update the stored counter.

Part 2.1: Implement RedisBadLoginAttemptsStorage

Complete these methods:

  • get(String key)
  • put(String key, Integer value)
  • increment(String key)
  • remove(String key)
  • setTtl(String key)

Expected behavior:

  • Use getKey(key) for every Redis operation so all keys are prefixed with bad_login:.
  • get returns 0 when Redis returns null.
  • put stores the value and refreshes the TTL.
  • increment increments the value and refreshes the TTL.
  • remove deletes the Redis key.
  • setTtl applies the configured TTL.

Useful Redis operations:

  • redisOperations.get(redisKey)
  • redisOperations.set(redisKey, value)
  • redisOperations.increment(redisKey)
  • redisOperations.getAndExpire(redisKey, ttl)
  • redisOperations.getOperations().delete(redisKey)

Run:

.\mvnw.cmd test "-Dtest=TaskNo2Test"

Task 3: Redis Task Queue Using Lists

Goal

Implement a Redis-backed task queue where each user has a separate FIFO queue.

FIFO means the first task pushed for a user is the first task popped for that user.

Part 3.1: Implement RedisTaskQueue

Complete these methods:

  • push(String user, String task)
  • pop(String user)
  • clear(String user)

Expected behavior:

  • Use getKey(user) for every Redis operation so all queue keys are prefixed with task:.
  • push appends a task to the user's queue.
  • pop returns and removes the oldest task from the user's queue.
  • pop returns null when the queue is empty.
  • clear deletes the user's queue.

Useful Redis operations:

  • redisOperations.rightPush(redisKey, task)
  • redisOperations.leftPop(redisKey)
  • redisOperations.getOperations().delete(redisKey)

Run:

.\mvnw.cmd test "-Dtest=TaskNo3Test"

Final Check

After completing all TODOs, run:

.\mvnw.cmd test

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors