Skip to content

fix(tasks): revalidate stale MMKV task cache on mount - #151

Merged
cybermax4200 merged 2 commits into
ecotask-network:mainfrom
devprom6:fix/task-feed-stale-cache-revalidation
Aug 28, 2026
Merged

fix(tasks): revalidate stale MMKV task cache on mount#151
cybermax4200 merged 2 commits into
ecotask-network:mainfrom
devprom6:fix/task-feed-stale-cache-revalidation

Conversation

@devprom6

Copy link
Copy Markdown
Contributor

Summary

The offline task feed cache (MMKV) had no TTL and no revalidation trigger. If the store held tasks from a previous session, useTaskFeed served them indefinitely and never called the API again — even on a fresh app start with connectivity. New tasks, status changes, and reward updates were invisible until a manual pull-to-refresh.

This adds a tasksLastFetchedAt timestamp and a mount-time stale check that silently revalidates the cache when it's older than TASK_FEED_STALE_MS (default 5 min).

Changes

src/store/taskStore.ts

  • Added tasksLastFetchedAt: string | null to TaskState and PersistedTaskSlice (persisted to MMKV).
  • setTasks stamps tasksLastFetchedAt with the current ISO time on every page-1 fetch.
  • sanitizePersistedTaskState passes tasksLastFetchedAt through (reset to null when the cache is empty).
  • reset() clears tasksLastFetchedAt.

src/hooks/useTaskFeed.ts

  • loadTasks(pageNum, silent = false) — silent mode skips the loading skeleton (setLoading).
  • Mount effect now computes isStale from tasksLastFetchedAt and, when the warm cache is older than TASK_FEED_STALE_MS, triggers a silent background fetch (loadTasks(1, true)).
  • selectedTask is never clobbered during revalidation because setTasks only replaces tasks.

src/config/taskFeedCache.ts (new)

  • Exports TASK_FEED_STALE_MS = 5 * 60 * 1000 as a separately-mockable module so tests can override the threshold.

Tests

  • useTaskFeed.test.ts / useTaskFeedRefetch.test.tsx: within-TTL → no fetch; past-TTL → silent fetch with no loading skeleton; selectedTask preserved after revalidation.
  • stores.test.ts: updated assertions for the new persisted field.

Acceptance Criteria

  • taskStore gains a tasksLastFetchedAt field, persisted to MMKV.
  • useTaskFeed triggers a background fetch on mount when tasksLastFetchedAt is older than TASK_FEED_STALE_MS (5 min default), even if the store has tasks.
  • The background fetch does not show a loading skeleton.
  • selectedTask is not clobbered during background revalidation.
  • Tests cover: (a) warm cache within TTL → no fetch, (b) warm cache past TTL → background fetch, (c) selectedTask preserved after revalidation.

Test plan

  • npm test — all task feed / store suites pass (48 tests).
  • npx tsc --noEmit and npx eslint clean.

Out of scope

  • Server-sent events / real-time task updates.
  • Per-filter TTL (all filters share the same tasksLastFetchedAt).

Closes #150

Add tasksLastFetchedAt timestamp to taskStore (persisted to MMKV) and
trigger a silent background fetch on mount when the warm cache is older
than TASK_FEED_STALE_MS (5 min). The revalidation shows no loading
skeleton and never clobbers selectedTask.

- taskStore: tasksLastFetchedAt set in setTasks, passed through
  sanitizePersistedTaskState, cleared on reset
- useTaskFeed: silent loadTasks mode + stale-check in mount effect
- TASK_FEED_STALE_MS extracted to mockable config module
- tests cover within-TTL (no fetch), past-TTL (silent fetch), and
  selectedTask preservation

@cybermax4200 cybermax4200 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent work!

@cybermax4200
cybermax4200 merged commit b2934cd into ecotask-network:main Aug 28, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] [Bug] useTaskFeed serves stale MMKV-cached tasks indefinitely — cached data is never revalidated on mount if the store is non-empty

2 participants