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
The rate limit counts per workspace, not per viewer: 120 requests per minute, on every plan. One refresh of this dashboard costs 2 Query API requests, so the limit permits a refresh every second. The route cache decides the real cost. The default of900 seconds costs 192 requests a
day and leaves the limit free for other clients of the workspace.
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 and makes its own requests. Move the cache to a shared store when many instances run.
- Put the dashboard behind your own authentication. The route answers any caller.
filterSet operators.