Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 8 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ on:
push:
branches: [main]
pull_request:
branches: "*"

jobs:
check_format:
strategy:
fail-fast: false
runs-on: ubuntu-latest
continue-on-error: false
steps:
- name: Download source
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install Crystal
uses: crystal-lang/install-crystal@v1
- name: Install shards
Expand All @@ -23,17 +19,15 @@ jobs:
run: crystal tool format --check
- name: Lint
run: ./bin/ameba
- name: Build shard entrypoint
run: crystal build src/lucky_cache_redis_store.cr

specs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
crystal_version: [latest]
include:
- os: ubuntu-latest
crystal_version: 1.4.0
runs-on: ${{ matrix.os }}
continue-on-error: false
crystal_version: ["1.16.3", latest]
runs-on: ubuntu-latest
services:
redis:
image: redis:7-alpine
Expand All @@ -45,11 +39,11 @@ jobs:
ports:
- 6379:6379
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: crystal-lang/install-crystal@v1
with:
crystal: ${{ matrix.crystal_version }}
- name: Install dependencies
run: shards install --skip-postinstall --skip-executables
- name: Run tests
run: crystal spec
run: crystal spec
8 changes: 5 additions & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ on:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: crystal-lang/install-crystal@v1
Expand All @@ -17,7 +19,7 @@ jobs:
- name: "Generate docs"
run: crystal docs
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
publish_dir: ./docs
32 changes: 23 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ A Redis storage backend for [LuckyCache](https://github.com/luckyframework/lucky

```yaml
dependencies:
lucky_cache:
github: luckyframework/lucky_cache
lucky_cache_redis_store:
github: luckyframework/lucky_cache_redis_store
```
Expand All @@ -19,9 +17,7 @@ A Redis storage backend for [LuckyCache](https://github.com/luckyframework/lucky
## Usage

```crystal
require "lucky_cache"
require "lucky_cache_redis_store"
require "redis"

LuckyCache.configure do |settings|
settings.storage = LuckyCache::RedisStore.new(
Expand Down Expand Up @@ -58,13 +54,26 @@ cache.delete("my_key")
cache.flush
```

## Expiration Semantics

- `expires_in` is stored with millisecond precision.
- TTL values must be at least `1.millisecond`.
- `0.seconds`, negative durations, and positive durations below `1.millisecond` raise `ArgumentError`.
- `read` restores cache items with their original TTL metadata and the correct absolute expiration time.

## Prefix Operations

- `flush` removes only keys that match the store's configured prefix.
- `size` counts only keys that match the configured prefix.
- Both operations iterate Redis with `SCAN`, not `KEYS`, so they remain safer on larger keyspaces.

### Supported Types

The Redis store supports the following types:
- Basic types: `String`, `Int32`, `Int64`, `Float64`, `Bool`, `Time`, `UUID`, `JSON::Any`
- Arrays of basic types: `Array(String)`, `Array(Int32)`, `Array(Int64)`, `Array(Float64)`, `Array(Bool)`

**Note:** Custom objects that include `LuckyCache::Cachable` are not supported by RedisStore due to serialization limitations. Use MemoryStore for caching custom objects.
**Note:** Custom objects that include `LuckyCache::Cacheable` are not supported by RedisStore due to serialization limitations. Use MemoryStore for caching custom objects.

### Workaround for Custom Objects

Expand All @@ -75,7 +84,10 @@ You can cache JSON representations of your objects:
# cache.write("user:123") { User.new("test@example.com") } # This will raise an error

# Cache a JSON representation
user_data = {"id" => 123, "email" => "test@example.com"}
user_data = {
"id" => JSON::Any.new(123_i64),
"email" => JSON::Any.new("test@example.com"),
}
cache.write("user:123") { JSON::Any.new(user_data) }

# Retrieve and reconstruct
Expand All @@ -87,14 +99,16 @@ user = User.new(cached_data["email"].as_s)

To run the tests:

1. Make sure Redis is running locally on the default port (6379)
1. Make sure Redis is running locally on the default port (`6379`)
2. Run `crystal spec`

The test suite includes tests for:
- Basic type caching
- Array type caching
- Expiration functionality
- Key deletion and cache flushing
- Millisecond TTL handling and TTL validation
- Expiration correctness after Redis deserialization
- Key deletion, prefix-scoped flushing, and prefix-scoped sizing
- Standalone shard loading
- Custom prefix support
- Error handling for non-serializable types

Expand Down
7 changes: 4 additions & 3 deletions shard.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
name: lucky_cache_redis_store
version: 0.1.0
version: 0.2.0

authors:
- Jeremy Woertink <jeremywoertink@gmail.com>

crystal: '>= 1.14.1'
crystal: ">= 1.16.3"

license: MIT

Expand All @@ -17,6 +17,7 @@ dependencies:
development_dependencies:
ameba:
github: crystal-ameba/ameba
version: ~> 1.5.0
version: ~> 1.6.4
timecop:
github: crystal-community/timecop.cr
version: ~> 0.5.0
Loading
Loading