Files
Create the project and install the chart library.
.env.local. Do not add a NEXT_PUBLIC_ prefix to the
key. A NEXT_PUBLIC_ variable is compiled into the browser bundle.
The API client
The client wraps the three endpoints. On a status code other than2xx, it throws a
GrainApiError that carries the status code and the Retry-After value.
The route
The route makes two Query API calls per refresh: one count and one query of up to 1,000 events. It keeps the last result in memory forCACHE_MS milliseconds. Every browser that opens the
dashboard inside that window gets the cached result, so the number of viewers does not change
the number of Query API calls.
The count card
The chart
The chart groups the events byeventDate and shows one point per day of the range.
The page
The page polls/api/metrics. If the route answers 429, the page waits for the number of
seconds in Retry-After before the next poll. The poll interval and the route cache use the
same number, so a poll inside the cache window costs no Query API call.
The poll interval
Rate limits count per API key, not per viewer. One refresh of this dashboard costs 2 Query API requests. The interval must satisfy both limits of the plan:- Minute rule:
interval >= 60 seconds * 2 / requests per minute. - Day rule:
interval >= 86,400 seconds * 2 / requests per day.
Set
NEXT_PUBLIC_DASHBOARD_REFRESH_SECONDS to the same value, so the browser does not poll
more often than the cache refreshes. A refresh that a user triggers by hand costs the same 2
requests and must count against the same budget.
Errors
Limits
Deployment
- Run
npm run build, then deploy withvercel. - Set
GRAIN_TENANT_ID,GRAIN_API_KEY,DASHBOARD_REFRESH_SECONDS, andNEXT_PUBLIC_DASHBOARD_REFRESH_SECONDSin the environment of the host. - If the host runs more than one instance, each instance holds its own cache. Divide the budget by the number of instances, or move the cache to a shared store.
- Put the dashboard behind your own authentication. The route answers any caller.
filterSet operators.