← Назад к главному
# feed.rs - Модуль для чтения/публикации тиков через Redis
## 📋 Назначение модуля
`Feed` - модуль для чтения/публикации тиков через Redis.
**Основная логика:**
1. **Чтение тика** - получает последний тик из Redis (`hb:last:{SYMBOL}`)
2. **Публикация тика** - публикует тик в Redis (`hb:ticks:{SYMBOL}`)
3. **История тиков** - хранит последние 1000 тиков в списке
**Используется в:**
- В будущем для чтения тиков (в текущей версии не используется)
---
## 🏗️ Структура модуля
### Структура `Feed`
**Строки:** 11-13
```rust
pub struct Feed {
redis: Arc,
}
```
**Поля:**
| Поле | Тип | Описание |
|------|-----|----------|
| `redis` | `Arc` | Клиент Redis |
---
## 🔄 Основные функции
### Функция `Feed::new()`
**Строки:** 16-18
**Сигнатура:**
```rust
pub fn new(redis: Arc) -> Self
```
**Возвращает:**
- `Feed` - новый экземпляр Feed
**Алгоритм:**
```rust
Feed { redis }
```
---
### Функция `Feed::get_tick_from_redis()`
**Строки:** 29-39
**Сигнатура:**
```rust
pub async fn get_tick_from_redis(&self, symbol: &str) -> Option
```
**Параметры:**
- `symbol` - символ контракта
**Возвращает:**
- `Some(Tick)` - последний тик
- `None` - тик не найден или ошибка
**Алгоритм:**
---
#### Этап 1: Получение подключения к Redis
**Строки:** 30-33
```rust
let mut conn = match get_redis_conn(&self.redis).await {
Ok(c) => c,
Err(_) => return None,
};
```
**Что делает:**
- Пытается получить подключение
- При ошибке → возвращает `None`
---
#### Этап 2: Формирование ключа
**Строка:** 35
```rust
let key = format!("hb:last:{}", symbol);
```
---
#### Этап 3: Получение тика из Redis
**Строки:** 37-38
```rust
let raw: Option = conn.get(&key).await.ok()?;
raw.and_then(|s| serde_json::from_str::(&s).ok())
```
**Что делает:**
- Получает строку из Redis по ключу `hb:last:{symbol}`
- Парсит строку в `Tick`
- Возвращает `Some(Tick)` или `None` при ошибке
**Пример ключа:**
```
hb:last:MEMES_USDT
```
**Пример значения:**
```json
{
"symbol": "MEMES_USDT",
"mid": 0.00200050,
"chg_pct": 45.5,
"ts": 1771747635,
"bid": 0.001990,
"ask": 0.002010,
"bid_qty": 50000.0,
"ask_qty": 48000.0
}
```
---
### Функция `Feed::publish_tick_to_redis()`
**Строки:** 46-55
**Сигнатура:**
```rust
pub async fn publish_tick_to_redis(&self, tick: &Tick)
```
**Параметры:**
- `tick` - тик для публикации
**Возвращает:**
- Ничего (возвращает при ошибке)
**Алгоритм:**
---
#### Этап 1: Получение подключения к Redis
**Строки:** 47-48
```rust
if let Ok(mut conn) = get_redis_conn(&self.redis).await {
```
**Что делает:**
- Пытается получить подключение
- При ошибке → возвращает
---
#### Этап 2: Формирование ключа
**Строка:** 48
```rust
let key_list = format!("hb:ticks:{}", tick.symbol);
```
**Пример ключа:**
```
hb:ticks:MEMES_USDT
```
---
#### Этап 3: Сериализация тика
**Строки:** 49
```rust
if let Ok(value) = serde_json::to_string(tick) {
```
---
#### Этап 4: Добавление тика в список
**Строки:** 50-52
```rust
let _: redis::RedisResult = conn.lpush(&key_list, &value).await;
// ограничиваем хвост до 1000 элементов
let _: redis::RedisResult = conn.ltrim(&key_list, 0, 999).await;
```
**Что делает:**
- `LPUSH` - добавляет тик в начало списка
- `LTRIM 0 999` - ограничивает список до 1000 элементов
---
## 📊 Redis ключи
| Ключ | Тип | Описание |
|------|-----|----------|
| `hb:last:{symbol}` | String | Последний тик (используется для чтения) |
| `hb:ticks:{symbol}` | List | Список тиков (максимум 1000, используется как история) |
---
## ⚠️ Критические моменты
### 1. Используется именно hb:last: для чтения
**Строки:** 26-28
```rust
/// Здесь используем именно hb:last:{SYMBOL}, чтобы:
/// - не дергать лишний раз список
/// - всегда брать актуальный последний тик O(1)
```
**Почему это важно:**
- `hb:last:{symbol}` - O(1) операция
- `hb:ticks:{symbol}` - список, доступ к последнему элементу O(N)
- Всегда берём актуальный последний тик
---
### 2. Публикация только в hb:ticks: (история)
**Строки:** 44-45
```rust
/// Здесь пишем ТОЛЬКО в hb:ticks:{SYMBOL}, как "историю",
/// last по-хорошему должен писать монитор или отдельный парсер.
```
**Что это значит:**
- `publish_tick_to_redis()` пишет только в `hb:ticks:{symbol}`
- `hb:last:{symbol}` должен писать монитор (monitor.rs)
---
### 3. Ошибки игнорируются
**Строки:** 32, 47
```rust
Err(_) => return None,
```
**Что это значит:**
- При ошибке Redis → возвращаем `None` или игнорируем
- Не паникуем, продолжаем работу
---
## 📚 Связанные файлы
| Файл | Связь |
|------|-------|
| `src/types.rs` | Структура Tick |
| `src/redis.rs` | Redis клиент |
| `src/monitor.rs` | Пишет в hb:last: и hb:ticks: |
---
## 🎯 Резюме
**Что делает feed.rs:**
1. ✅ Читает последний тик из Redis (`hb:last:{symbol}`)
2. ✅ Публикует тик в Redis (`hb:ticks:{symbol}`)
3. ✅ Хранит историю последних 1000 тиков
**Feed методы:**
- `new(redis)` - создание Feed
- `get_tick_from_redis(symbol)` - получить последний тик
- `publish_tick_to_redis(tick)` - опубликовать тик
**Redis ключи:**
- `hb:last:{symbol}` - последний тик (для чтения)
- `hb:ticks:{symbol}` - список тиков (история, максимум 1000)
**Критические моменты:**
- 🔥 Для чтения используем `hb:last:` (O(1) операция)
- 🔥 Для публикации пишем в `hb:ticks:` (история)
- 🔥 Ошибки Redis игнорируются
---
**Дата создания:** 2026-02-22
**Автор:** Claude Code Assistant
**Версия:** 1.0