All Products
Search
Document Center

Tair (Redis® OSS-Compatible):Manage multi-device user logon with TairHash

Last Updated:Mar 30, 2026

TairHash is an in-house extended data structure of Tair that allows you to specify the time-to-live (TTL) and version number for each field. When a single user logs in from multiple devices, storing each session as a Redis string forces you to concatenate the user ID and device type into one key — for example, User_1_phone. TairHash eliminates this workaround by mapping the session structure directly to its data model: set key to the user ID, field to the device type, and value to the session token. Because TairHash supports TTL settings for both keys and fields, tokens expire independently per device with no extra application logic.

Why standard Redis strings fall short

For single-device sessions, Redis strings work well. Multi-device sessions expose three problems:

Problem Impact
String concatenation Your application must build and parse composite keys like user_1_phone on every read and write
Encoding overhead Repeated key parsing increases CPU and code complexity
Storage duplication The user ID prefix is repeated across every device-specific key

TairHash resolves all three: one key per user, one field per device, one TTL per field.

Comparison between Redis strings and TairHash

Use cases

Field-level TTL in TairHash fits several session management patterns:

  • Multi-device token management: Store one token per device under a single user key. Each token expires independently based on that device's session activity.

  • Active session tracking: Use EXHGETALL to list all live sessions for a user. Expired fields are automatically excluded, so the result always reflects the current active state.

  • Automatic session cleanup: Set a short TTL on tokens at login. When a user is inactive on a device longer than the TTL, that session is removed without any scheduled cleanup job.

Key commands

Purpose Command Description
Write a token with TTL EXHSET key field value EX seconds Sets a field-level TTL in seconds
Read all active tokens EXHGETALL key Returns only fields that have not expired

Prerequisites

Before you begin, ensure that you have:

  • A Tair instance (Alibaba Cloud Redis with Tair extensions enabled)

  • Python 3.8 or later

  • tair-py installed (pip3 install tair) — source available at github.com/alibaba/tair-py

Store and retrieve session tokens

The following example stores tokens for two users across multiple devices, waits 6 seconds, then retrieves the remaining active tokens. After 6 seconds, user1's phone token (TTL = 5 s) has expired and is excluded from the results.

# -*- coding: utf-8 -*-
#!/usr/bin/env python
import os
import time
from tair import Tair
from tair import ResponseError


def get_tair() -> Tair:
    # Connect to a Tair instance.
    # host: endpoint of your Tair instance
    # port: default is 6379
    # username: leave blank to use the default account
    # password: read from environment variable TAIR_PASSWORD
    return Tair(
        host="r-bp************.redis.rds.aliyuncs.com",
        port=6379,
        db=0,
        username="",
        password=os.environ.get("TAIR_PASSWORD"),
    )


def add_user_token(tair: Tair, user_id: str, device: str, token: str, ttl_seconds: int) -> bool:
    # Store a session token using EXHSET with a per-field TTL.
    # key   = user_id  (groups all devices for one user)
    # field = device   (identifies the device type)
    # value = token    (the session token)
    # ex    = TTL in seconds
    try:
        result = tair.exhset(user_id, device, token, ex=ttl_seconds)
        return result == 1
    except ResponseError as e:
        print(e)
        return False


def print_active_tokens(tair: Tair, user_id: str):
    # EXHGETALL returns only fields that have not yet expired.
    for entry in tair.exhgetall(user_id):
        print("{}:{}".format(user_id, entry))


if __name__ == "__main__":
    tair = get_tair()

    user_1 = "user1"
    user_2 = "user2"

    # Write four tokens with different TTLs.
    add_user_token(tair, user_1, "phone", "token_123", 5)   # expires in 5 s
    add_user_token(tair, user_1, "pad",   "token_124", 10)  # expires in 10 s
    add_user_token(tair, user_2, "pad",   "token_456", 10)  # expires in 10 s
    add_user_token(tair, user_2, "pc",    "token_457", 10)  # expires in 10 s

    # Wait 6 seconds. user1's phone token (TTL = 5 s) will have expired.
    print("Waiting 6 seconds...")
    time.sleep(6)

    # Only 3 of the 4 tokens are returned; user1/phone has expired.
    print_active_tokens(tair, user_1)  # prints user1/pad only
    print_active_tokens(tair, user_2)  # prints user2/pad and user2/pc

Expected output:

Waiting 6 seconds...
user1:{field: pad, value: token_124}
user2:{field: pad, value: token_456}
user2:{field: pc, value: token_457}

user1/phone is absent because its 5-second TTL elapsed before the query. The remaining three tokens, each set with a 10-second TTL, are still active.

Related topics