import { cn } from 'ui' import { MetricCard, MetricCardContent, MetricCardHeader, MetricCardLabel, MetricCardValue, } from 'ui-patterns/MetricCard' import { getConnectionMetrics } from './DatabaseConnections.utils' import { useSelectActivityPid } from './useSelectActivityPid' import { formatDuration } from '@/components/interfaces/QueryPerformance/QueryPerformance.utils' import { useDatabaseRolesQuery } from '@/data/database-roles/database-roles-query' import { useDatabaseActivityQuery } from '@/data/database/activity-query' import { useMaxConnectionsQuery } from '@/data/database/max-connections-query' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { useTrack } from '@/lib/telemetry/track' interface OverviewProps { live?: boolean } export const Overview = ({ live }: OverviewProps) => { const track = useTrack() const { data: project } = useSelectedProjectQuery() const { selectPid } = useSelectActivityPid() const { data, isPending: isLoadingActivity } = useDatabaseActivityQuery( { projectRef: project?.ref, connectionString: project?.connectionString, }, { refetchOnWindowFocus: live, refetchInterval: live ? 3000 : false } ) const { activeQueries, blockedQueries, warnBlockedQueries, longestBlockedQuery, idleInTransactionQueries, longestRunningQuery, warnLongestRunningQuery, queryBlockingTheMostQueries, warnTopBlocker, } = getConnectionMetrics(data ?? []) const { data: roles, isPending: isLoadingRoles } = useDatabaseRolesQuery( { projectRef: project?.ref, connectionString: project?.connectionString, }, { refetchOnWindowFocus: live, refetchInterval: live ? 3000 : false } ) const rolesWithActiveConnections = (roles ?? []).filter((role) => role.activeConnections) const totalActiveConnections = (roles ?? []) .map((role) => role.activeConnections) .reduce((a, b) => a + b, 0) const { data: maxConnectionLimit, isPending: isLoadingMaxConnections } = useMaxConnectionsQuery( { projectRef: project?.ref, connectionString: project?.connectionString, }, { select: (data) => data.maxConnections, refetchInterval: live ? 3000 : false, } ) const onSelectLongestBlocked = () => { if (!longestBlockedQuery) return track('database_connections_overview_metric_card_clicked', { type: 'longest_blocked' }) selectPid(longestBlockedQuery.activity.pid) } const onSelectTopBlocker = () => { if (!queryBlockingTheMostQueries) return track('database_connections_overview_metric_card_clicked', { type: 'top_blocker' }) selectPid(queryBlockingTheMostQueries.activity.pid) } const onSelectLongestRunning = () => { if (!longestRunningQuery) return track('database_connections_overview_metric_card_clicked', { type: 'longest_running' }) selectPid(longestRunningQuery.activity.pid) } return (
Connections by roles:
| {role.name}: | {role.activeConnections} |
|---|
Transactions left open without running a query, which can hold locks and block table cleanup for as long as it stays open
Typically indicates an app issue, such as a forgotten COMMIT or ROLLBACK.
> } > Idle in transactionQueries waiting on a lock held by another session - stalls everything queued behind it.
Typically caused by a slow transaction, a long-running migration, or a stuck idle-in-transaction session.
> } > Blocked queries