Skip to content

Commit d3155d3

Browse files
committed
Cache calls to /signers/tickers in Explorer
1 parent 74c8f25 commit d3155d3

File tree

3 files changed

+62
-10
lines changed

3 files changed

+62
-10
lines changed

mithril-explorer/src/app/page.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import SnapshotsList from '../components/Artifacts/SnapshotsList';
1111
import MithrilStakeDistributionsList from "../components/Artifacts/MithrilStakeDistributionsList";
1212
import {aggregatorSearchParam} from "../constants";
1313
import {selectAggregator, selectedAggregator as currentlySelectedAggregator} from "../store/settingsSlice";
14-
import {updatePoolsForAggregator} from "../store/poolsSlice";
14+
import {refreshPoolsCaches, updatePoolsForAggregator} from "../store/poolsSlice";
1515

1616
// Disable SSR for the following components since they use data from the store that are not
1717
// available server sides (because those data can be read from the local storage).
@@ -27,7 +27,6 @@ export default function Explorer() {
2727
const [isUpdatingAggregatorInUrl, setIsUpdatingAggregatorInUrl] = useState(false);
2828
const selectedAggregator = useSelector(currentlySelectedAggregator);
2929

30-
3130
// Update the aggregator in the url query
3231
useEffect(() => {
3332
const aggregatorInUrl = searchParams.get(aggregatorSearchParam);
@@ -40,6 +39,7 @@ export default function Explorer() {
4039
router.push("?" + params.toString(), undefined, {shallow: true});
4140
}
4241

42+
dispatch(refreshPoolsCaches());
4343
dispatch(updatePoolsForAggregator(selectedAggregator));
4444
}, [selectedAggregator]);
4545

mithril-explorer/src/app/registrations/page.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Stake from "../../components/Stake";
1313
import RawJsonButton from "../../components/RawJsonButton";
1414
import VerifiedBadge from "../../components/VerifiedBadge";
1515
import PoolTicker from "../../components/PoolTicker";
16-
import {updatePoolsForAggregator} from "../../store/poolsSlice";
16+
import {refreshPoolsCaches, updatePoolsForAggregator} from "../../store/poolsSlice";
1717
import PartyId from "../../components/PartyId";
1818

1919
Chart.register(
@@ -80,6 +80,7 @@ export default function Registrations() {
8080
console.error("Fetch current epoch in epoch-settings error:", error);
8181
});
8282

83+
dispatch(refreshPoolsCaches());
8384
dispatch(updatePoolsForAggregator(aggregator));
8485
} else {
8586
setCurrentError(error);

mithril-explorer/src/store/poolsSlice.js

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
11
import {createAsyncThunk, createSelector, createSlice} from "@reduxjs/toolkit";
22

3+
const CACHE_NAME = "v1";
4+
// Delete all caches older than 6 hours
5+
const cacheRefreshIntervalInMilliseconds = 6 * 3600 * 1000;
6+
37
export const poolsSlice = createSlice({
48
name: 'pools',
59
initialState: { list: [] },
6-
reducers: {},
10+
reducers: {
11+
refreshPoolsCaches: (state) => {
12+
const now = Date.now();
13+
for (const entry of state.list.map(p => ({date: p.date, url: poolTickersUrl(p.aggregator)}))) {
14+
const millisecondsSinceLastRefresh = now - entry.date;
15+
16+
if (millisecondsSinceLastRefresh > cacheRefreshIntervalInMilliseconds) {
17+
caches.open(CACHE_NAME).then(async (cache) => {
18+
const deletionSuccessful = await cache.delete(entry.url);
19+
if (!deletionSuccessful) {
20+
console.error(`Failed to delete cache: ${entry.url}`);
21+
}
22+
});
23+
}
24+
}
25+
}
26+
},
727
extraReducers: builder => builder.addCase(updatePoolsForAggregator.fulfilled, (state, action) => {
828
let existing = poolsForAggregator(state, action.payload.aggregator);
929

1030
if (existing) {
11-
existing.date = action.payload.date;
31+
existing.network = action.payload.network;
1232
existing.pools = action.payload.pools;
1333
} else {
1434
state.list.push({
@@ -21,22 +41,53 @@ export const poolsSlice = createSlice({
2141
})
2242
});
2343

44+
export const {
45+
refreshPoolsCaches
46+
} = poolsSlice.actions;
47+
48+
const poolTickersUrl = aggregator => `${aggregator}/signers/tickers`;
49+
2450
export const updatePoolsForAggregator = createAsyncThunk('pools/updateForAggregator', aggregator => {
25-
return fetch(`${aggregator}/signers/tickers`)
51+
const url = poolTickersUrl(aggregator);
52+
return caches.match(url)
53+
.then(cached => {
54+
// Cache hit
55+
if (cached) {
56+
return cached;
57+
}
58+
59+
// Cache miss
60+
return fetch(url).then(response => {
61+
if (response.status === 200) {
62+
caches.open(CACHE_NAME).then(async (cache) => {
63+
const putSuccessful = await cache.put(url, response);
64+
if (!putSuccessful) {
65+
console.error(`Failed to put cache: ${url}`);
66+
}
67+
});
68+
}
69+
return response.clone();
70+
})
71+
})
2672
.then(response => response.status === 200 ? response.json() : {})
2773
.then(data => {
2874
return {
2975
aggregator: aggregator,
3076
date: Date.now(),
3177
network: data.network,
32-
pools: data.signers,
78+
pools: data.signers ?? [],
3379
};
3480
});
3581
});
3682

37-
const poolsForAggregator = (state, aggregator) => {
38-
return state.list.find(poolsData => poolsData.aggregator === aggregator);
39-
};
83+
const poolsForAggregator = createSelector( [
84+
state => state.pools,
85+
(state, aggregator) => aggregator
86+
],
87+
(pools, aggregator) => {
88+
return pools.list.find(poolsData => poolsData.aggregator === aggregator);
89+
}
90+
);
4091

4192
export const getPool = createSelector([
4293
state => state.pools,

0 commit comments

Comments
 (0)