Skip to main content

How to build a Real-Time Leaderboard app Using Redis


Profile picture for Ajeet Raina
Author:
Ajeet Raina, Former Developer Growth Manager at Redis

The concept of a leaderboard—a scoreboard showing the ranked names and current scores (or other data points) of the leading competitors—is essential to the world of computer gaming, but leaderboards are now about more than just games. They are about gamification, a broader implementation that can include any group of people with a common goal (coworkers, students, sales groups, fitness groups, volunteers, and so on).

Leaderboards can encourage healthy competition in a group by openly displaying the current ranking of each group member. They also provide a clear way to view the ongoing achievements of the entire team as members move towards a goal. Gamification of tasks and goals via leaderboards is a great way to motivate people by providing them with constant feedback of where they rank in comparison to other group members. Done well, this can lead to healthy competition that builds group cohesion.

My Image

Step 1. Install the below software

Step 2. Clone the repository

git clone https://github.com/redis-developer/basic-redis-leaderboard-demo-java

Step 3. Run docker compose

docker network create global
docker-compose up -d --build

Step 4. Verifying if containers are up and running

 docker-compose ps
Name Command State Ports
--------------------------------------------------------------------------------------------------
redis.redisleaderboard.docker docker-entrypoint.sh redis ... Up 127.0.0.1:55000->6379/tcp

Step 5. Copy .env.example to create .env

Provide the values for environment variables (if needed)

- REDIS_URL: Redis database endpoint URL
- REDIS_HOST: Redis server host
- REDIS_PORT: Redis server port
- REDIS_DB: Redis server db index
- REDIS_PASSWORD: Redis server password

If you're using Redis Cloud, you must supply DB endpoint, password, port and the name of the database. In case of local system, the entries look like as shown below:

REDIS_URL=
REDIS_HOST=redis://localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=

Step 6. Run the backend

  • Install gradle

Follow the following link https://gradle.org/install/ for your MacOS

brew install gradle
  • Install JDK

Follow the following link https://docs.oracle.com/javase/10/install/installation-jdk-and-jre-macos.htm for your MacOS

export $(cat .env | xargs)

Step 7. Run the wrapper task

To use Wrapper, we need to generate some particular files. We'll generate these files using the built-in Gradle task called wrapper. Note that we need to generate these files only once.

Now, let's run the wrapper task in our project directory:

gradle wrapper

It should show the below results:

Welcome to Gradle 6.8.3!

Here are the highlights of this release:
- Faster Kotlin DSL script compilation
- Vendor selection for Java toolchains
- Convenient execution of tasks in composite builds
- Consistent dependency resolution

For more details see https://docs.gradle.org/6.8.3/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

BUILD SUCCESSFUL in 29s
1 actionable task: 1 executed

Step 8. Perform the build task

The Gradle Wrapper is now available for building your project. It's time to run the wrapper script to perform the build task.

./gradlew build
% ./gradlew build
Downloading https://services.gradle.org/distributions/gradle-6.8.3-bin.zip
..........10%..........20%..........30%...........40%..........50%..........60%..........70%...........80%..........90%..........100%
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

> Task :test
2021-03-01 07:08:42.962 INFO 3624 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'

BUILD SUCCESSFUL in 1m 13s
12 actionable tasks: 12 executed

Step 9. Run your application

./gradlew run
> Task :run

. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.4.1)

2021-03-01 07:09:59.610 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : Starting BasicRedisLeaderLoardDemoJavaApplication using Java 13.0.2 on Ajeets-MacBook-Pro.local with PID 3672 (/Users/ajeetraina/projects/basic-redis-leaderboard-demo-java/build/classes/java/main started by ajeetraina in /Users/ajeetraina/projects/basic-redis-leaderboard-demo-java)
2021-03-01 07:09:59.614 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : No active profile set, falling back to default profiles: default
2021-03-01 07:09:59.661 INFO 3672 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2021-03-01 07:09:59.661 INFO 3672 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2021-03-01 07:10:00.481 INFO 3672 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 5000 (http)
2021-03-01 07:10:00.492 INFO 3672 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-03-01 07:10:00.492 INFO 3672 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.41]
2021-03-01 07:10:00.551 INFO 3672 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-03-01 07:10:00.551 INFO 3672 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 889 ms
2021-03-01 07:10:00.756 INFO 3672 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2021-03-01 07:10:00.845 INFO 3672 --- [ restartedMain] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page: URL [file:/Users/ajeetraina/projects/basic-redis-leaderboard-demo-java/assets/index.html]
2021-03-01 07:10:00.949 INFO 3672 --- [ restartedMain] .s.s.UserDetailsServiceAutoConfiguration :

Using generated security password: ea2d5326-b04c-4f93-b771-57bcb53f656e

2021-03-01 07:10:01.016 INFO 3672 --- [ restartedMain] o.s.s.web.DefaultSecurityFilterChain : Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@583fa06c, org.springframework.security.web.context.SecurityContextPersistenceFilter@524c0386, org.springframework.security.web.header.HeaderWriterFilter@c6e5d4e, org.springframework.security.web.authentication.logout.LogoutFilter@3e1f33e9, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@6790427f, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@40ddf86, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@1412ffa9, org.springframework.security.web.session.SessionManagementFilter@3eb6c20f, org.springframework.security.web.access.ExceptionTranslationFilter@21646e94, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@649e1b25]
2021-03-01 07:10:01.043 INFO 3672 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2021-03-01 07:10:01.065 INFO 3672 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 5000 (http) with context path ''
2021-03-01 07:10:01.093 INFO 3672 --- [ restartedMain] BasicRedisLeaderLoardDemoJavaApplication : Started BasicRedisLeaderLoardDemoJavaApplication in 1.937 seconds (JVM running for 2.327)
<=========----> 75% EXECUTING [17s]
> :run

Step 10. Access the leaderboard application

My Image

How it works?

How the data is stored:

  • The AAPL's details - market cap of 2.6 triillions and USA origin - are stored in a hash like below:

     HSET "company:AAPL" symbol "AAPL" market_cap "2600000000000" country USA
  • The Ranks of AAPL of 2.6 trillions are stored in a ZSET.

     ZADD  companyLeaderboard 2600000000000 company:AAPL

How the data is accessed:

  • Top 10 companies:

     ZREVRANGE companyLeaderboard 0 9 WITHSCORES
  • All companies:

     ZREVRANGE companyLeaderboard 0 -1 WITHSCORES
  • Bottom 10 companies:

     ZRANGE companyLeaderboard 0 9 WITHSCORES
  • Between rank 10 and 15:

     ZREVRANGE companyLeaderboard 9 14 WITHSCORES
  • Show ranks of AAPL, FB and TSLA:

     ZREVRANGE  companyLeaderBoard company:AAPL company:FB company:TSLA
  • Adding 1 billion to market cap of FB company:

     ZINCRBY companyLeaderBoard 1000000000 "company:FB"
  • Reducing 1 billion of market cap of FB company:

     ZINCRBY companyLeaderBoard -1000000000 "company:FB"
  • Companies between 500 billion and 1 trillion:

     ZCOUNT companyLeaderBoard 500000000000 1000000000000
  • Companies over a Trillion:

     ZCOUNT companyLeaderBoard 1000000000000 +inf

References