moar. Session pooler is de-prioritized

This commit is contained in:
Jonathan Summers-Muir committed 2024-11-21 14:30:36 +08:00
1 parent 7cb2114025
commit c96b87ff19
4 files changed
+279 -131

No files matched your search

@@ -7,10 +7,11 @@ import {
CollapsibleContent_Shadcn_,
CollapsibleTrigger_Shadcn_,
DIALOG_PADDING_X,
WarningIcon,
} from 'ui'
import { Input } from 'ui-patterns/DataInputs/Input'
import { ConnectionParameters } from './ConnectionParameters'
import { SessionIcon, TransactionIcon } from './pooler-icons-v2'
import { DirectConnectionIcon, SessionIcon, TransactionIcon } from './pooler-icons-v2'
import { ChevronRight } from 'lucide-react'
interface ConnectionPanelProps {
@@ -25,7 +26,7 @@ interface ConnectionPanelProps {
description?: string
link?: { text: string; url: string }
}
notice?: string
notice?: string[]
parameters?: Array<{
key: string
value: string
@@ -106,140 +107,176 @@ export const ConnectionPanel = ({
fileTitle,
}: ConnectionPanelProps) => {
return (
<div className={cn('py-8', DIALOG_PADDING_X)}>
<div className="flex flex-col gap-5 lg:grid lg:grid-cols-2 lg:gap-20 w-full">
<div className="flex flex-col">
<h1 className="text-sm mb-2">{title}</h1>
<p className="text-xs text-foreground-light mb-4">{description}</p>
<div className="flex flex-col -space-y-px">
{/* {contentType === 'input' ? ( */}
{false ? (
<Input
copy
readOnly
className="text-xs dark:bg-alternative font-mono input-mono [&>div>div>div>input]:text-xs [&>div>div>div>input]:opacity-100 rounded-b-none"
<div className="flex flex-col gap-5 lg:grid lg:grid-cols-2 lg:gap-20 w-full">
<div className="flex flex-col">
<h1 className="text-sm mb-2">{title}</h1>
<p className="text-sm text-foreground-light mb-4">{description}</p>
<div className="flex flex-col -space-y-px">
{/* {contentType === 'input' ? ( */}
{false ? (
<Input
copy
readOnly
className="text-xs dark:bg-alternative font-mono input-mono [&>div>div>div>input]:text-xs [&>div>div>div>input]:opacity-100 rounded-b-none"
value={connectionString}
onCopy={onCopy}
/>
) : (
<>
{fileTitle && <CodeBlockFileHeader title={fileTitle} />}
<CodeBlock
wrapperClassName={cn(
'[&_pre]:rounded-b-none [&_pre]:px-4 [&_pre]:py-3',
fileTitle && '[&_pre]:rounded-t-none'
)}
language={lang}
value={connectionString}
onCopy={onCopy}
className="[&_code]:text-[12px] [&_code]:text-foreground"
hideLineNumbers
/>
) : (
<>
{fileTitle && <CodeBlockFileHeader title={fileTitle} />}
<CodeBlock
wrapperClassName={cn(
'[&_pre]:rounded-b-none [&_pre]:px-4 [&_pre]:py-3',
fileTitle && '[&_pre]:rounded-t-none'
)}
language={lang}
value={connectionString}
className="[&_code]:text-[12px] [&_code]:text-foreground"
hideLineNumbers
/>
</>
)}
{notice && (
<div className="border px-3 py-0.5 w-full justify-start rounded-t-none !last:rounded-b group-data-[state=open]:rounded-b-none border-light">
<span className="text-xs text-foreground-lighter">{notice}</span>
</div>
)}
{parameters.length > 0 && <ConnectionParameters parameters={parameters} />}
</div>
</>
)}
{notice && (
<div className="border px-4 py-1 w-full justify-start rounded-t-none !last:rounded-b group-data-[state=open]:rounded-b-none border-light">
{notice?.map((text: string) => (
<p key={text} className="text-xs text-foreground-lighter">
{text}
</p>
))}
</div>
)}
{parameters.length > 0 && <ConnectionParameters parameters={parameters} />}
</div>
<div className="flex flex-col items-end">
<div className="flex flex-col -space-y-px w-full">
{type !== 'direct' && (
<>
<div className="relative border border-muted px-5 flex items-center gap-3 py-3 first:rounded-t last:rounded-b h-[58px]">
<div className="absolute top-2 left-2.5">
{type === 'transaction' ? <TransactionIcon /> : <SessionIcon />}
</div>
<div className="flex flex-col pl-[52px]">
<span className="text-xs text-foreground">
{type === 'transaction'
? 'Suitable for a large number of connected clients'
: 'Not suitable if you have a large number of clients'}
</span>
</div>
</div>
<div className="flex flex-col items-end">
<div className="flex flex-col -space-y-px w-full">
{type !== 'session' && (
<>
<div className="relative border border-muted px-5 flex items-center gap-3 py-3 first:rounded-t last:rounded-b h-[58px]">
<div className="absolute top-2 left-2.5">
{type === 'transaction' ? <TransactionIcon /> : <DirectConnectionIcon />}
</div>
<div className="border border-muted px-5 flex items-center gap-3 py-3 first:rounded-t last:rounded-b h-[58px]">
<div className="flex flex-col pl-[52px]">
<span className="text-xs text-foreground">
{type === 'transaction'
? 'Pre-warmed connection pool to the database'
: 'Connections from the pooler are not shared'}
</span>
</div>
<div className="flex flex-col pl-[52px]">
<span className="text-xs text-foreground">
{type === 'transaction'
? 'Suitable for a large number of connected clients'
: 'Suitable for long-lived, persistent connections'}
</span>
</div>
</>
)}
</div>
<div className="border border-muted px-5 flex items-center gap-3 py-3 first:rounded-t last:rounded-b h-[58px]">
<div className="flex flex-col pl-[52px]">
<span className="text-xs text-foreground">
{type === 'transaction'
? 'Pre-warmed connection pool to Postgres'
: 'Each client has a dedicated connection to Postgres'}
</span>
</div>
</div>
</>
)}
<div className="border border-muted px-5 flex gap-7 items-center py-3 first:rounded-t last:rounded-b">
<div className="flex items-center gap-2">
<IPv4StatusIcon active={ipv4Status.type === 'success'} />
<div className="border border-muted px-5 flex gap-7 items-center py-3 first:rounded-t last:rounded-b">
<div className="flex items-center gap-2">
<IPv4StatusIcon active={ipv4Status.type === 'success'} />
</div>
<div className="flex flex-col">
<span className="text-xs text-foreground">{ipv4Status.title}</span>
{ipv4Status.description && (
<span className="text-xs text-foreground-lighter">{ipv4Status.description}</span>
)}
{/* {ipv4Status.type === 'success' && type !== 'transaction' && (
<span className="text-xs text-foreground-lighter">
Use Direct Connection if on a IPv6 network
</span>
)} */}
{ipv4Status.type === 'error' && (
<span className="text-xs text-foreground-lighter">
Use Session Pooler if on a IPv4 network or purchase IPv4 addon
</span>
)}
{ipv4Status.link && (
<div className="mt-2">
<Button className="" type="default" size="tiny">
<a
href={ipv4Status.link.url}
className="text-xs text-light hover:text-foreground"
>
{ipv4Status.link.text}
</a>
</Button>
</div>
)}
</div>
</div>
{type === 'session' && (
<div className="border border-muted px-5 flex gap-7 items-center py-3 first:rounded-t last:rounded-b bg-alternative/50">
<div className="flex w-6 h-6 rounded items-center justify-center gap-2 flex-shrink-0 bg-surface-100">
<WarningIcon />
</div>
<div className="flex flex-col">
<span className="text-xs text-foreground">{ipv4Status.title}</span>
{ipv4Status.description && (
<span className="text-xs text-foreground-lighter">{ipv4Status.description}</span>
)}
{ipv4Status.link && (
<a
href={ipv4Status.link.url}
className="text-xs text-light hover:text-foreground"
>
{ipv4Status.link.text}
</a>
)}
<span className="text-xs text-foreground">Only use on a IPv4 network</span>
<span className="text-xs text-foreground-lighter">
Use Direct Connection if connecting via a IPv6 network
</span>
</div>
</div>
)}
{ipv4Status.type === 'error' && (
<Collapsible_Shadcn_ className="group -space-y-px">
<CollapsibleTrigger_Shadcn_
asChild
className="group/collapse w-full justify-start rounded-t-none !last:rounded-b group-data-[state=open]:rounded-b-none border-muted"
{ipv4Status.type === 'error' && (
<Collapsible_Shadcn_ className="group -space-y-px">
<CollapsibleTrigger_Shadcn_
asChild
className="group/collapse w-full justify-start rounded-t-none !last:rounded-b group-data-[state=open]:rounded-b-none border-muted"
>
<Button
type="default"
size="tiny"
className="text-foreground-lighter !bg-dash-sidebar"
icon={
<ChevronRight
size={12}
className={cn(
'group-data-[state=open]/collapse:rotate-90 text-foreground-muted transition-transform'
)}
/>
}
>
<Button
type="default"
size="tiny"
className="text-foreground-lighter !bg-dash-sidebar"
icon={
<ChevronRight
size={12}
className={cn(
'group-data-[state=open]/collapse:rotate-90 text-foreground-muted transition-transform'
)}
/>
}
>
Some platforms are IPv4-only:
</Button>
</CollapsibleTrigger_Shadcn_>
<CollapsibleContent_Shadcn_ className="bg-dash-sidebar rounded-b border px-3 py-2">
<div className="flex flex-col gap-2">
<p className="text-xs text-foreground-light max-w-xs">
A few major platforms are IPv4-only and may not work with a Direct Connection:
</p>
<div className="flex gap-4">
<div className="text-foreground text-xs">Retool</div>
<div className="text-foreground text-xs">GitHub Actions</div>
<div className="text-foreground text-xs">Vercel</div>
<div className="text-foreground text-xs">Render</div>
</div>
<p className="text-xs text-foreground-lighter max-w-xs">
If you wish to use a Direct Connection with these please purchase{' '}
<a
href={ipv4Status?.link?.url}
className="text-xs text-light hover:text-foreground"
>
IPv4 support
</a>
.
</p>
Some platforms are IPv4-only:
</Button>
</CollapsibleTrigger_Shadcn_>
<CollapsibleContent_Shadcn_ className="bg-dash-sidebar rounded-b border px-3 py-2">
<div className="flex flex-col gap-2">
<p className="text-xs text-foreground-light max-w-xs">
A few major platforms are IPv4-only and may not work with a Direct Connection:
</p>
<div className="flex gap-4">
<div className="text-foreground text-xs">Vercel</div>
<div className="text-foreground text-xs">GitHub Actions</div>
<div className="text-foreground text-xs">Render</div>
<div className="text-foreground text-xs">Retool</div>
</div>
</CollapsibleContent_Shadcn_>
</Collapsible_Shadcn_>
)}
</div>
<p className="text-xs text-foreground-lighter max-w-xs">
If you wish to use a Direct Connection with these please purchase{' '}
<a
href={ipv4Status?.link?.url}
className="text-xs text-light hover:text-foreground"
>
IPv4 support
</a>
.
</p>
<p className="text-xs text-foreground-lighter max-w-xs">
You may also use the{' '}
<span className="text-foreground-light">Session Pooler</span> or{' '}
<span className="text-foreground-light">Transaction Pooler</span> if you are on
a IPv4 network.
</p>
</div>
</CollapsibleContent_Shadcn_>
</Collapsible_Shadcn_>
)}
</div>
</div>
</div>
@@ -39,7 +39,7 @@ export const ConnectionParameters = ({ parameters }: ConnectionParametersProps)
<Collapsible_Shadcn_ open={isOpen} onOpenChange={setIsOpen} className="group -space-y-px">
<CollapsibleTrigger_Shadcn_
asChild
className="w-full justify-start rounded-t-none !last:rounded-b group-data-[state=open]:rounded-b-none border-light"
className="w-full justify-start rounded-t-none !last:rounded-b group-data-[state=open]:rounded-b-none border-light px-3"
>
<Button
type="default"
@@ -39,6 +39,7 @@ import {
getPoolerTld,
} from './DatabaseSettings.utils'
import examples, { Example } from './DirectConnectionExamples'
import { Admonition } from 'ui-patterns'
const CONNECTION_TYPES: {
id: ConnectionType
@@ -307,7 +308,7 @@ export const DatabaseConnectionString = () => {
<StepLabel number={++stepNumber}>Choose type of connection</StepLabel>
</div>
)}
<div className="divide-y divide-border-muted">
<div className="divide-y divide-border-muted [&>div]:px-7 [&>div]:py-8">
<ConnectionPanel
contentType={contentType}
lang={lang}
@@ -320,13 +321,14 @@ export const DatabaseConnectionString = () => {
ipv4Status={{
type: !ipv4Addon ? 'error' : 'success',
title: !ipv4Addon ? 'Not IPv4 compatible' : 'IPv4 compatible',
description: ipv4Addon && 'Connections are IPv4 proxied with IPv4 addon.',
link: !ipv4Addon
? {
text: 'Purchase IPv4 support',
text: 'IPv4 addon',
url: `/project/${projectRef}/settings/addons?panel=ipv4`,
}
: {
text: 'Update IPv4 settings',
text: 'IPv4 settings',
url: `/project/${projectRef}/settings/addons?panel=ipv4`,
},
}}
@@ -347,7 +349,7 @@ export const DatabaseConnectionString = () => {
type="transaction"
title="Transaction pooler"
fileTitle={fileTitle}
description="Ideal for stateless applications like serverless functions where each interaction with the database is brief and isolated."
description="Ideal for stateless applications like serverless functions where each interaction with Postgres is brief and isolated."
connectionString={connectionStrings['pooler'][selectedTab]}
onCopy={() => handleCopy(selectedTab)}
ipv4Status={{
@@ -355,7 +357,7 @@ export const DatabaseConnectionString = () => {
title: 'IPv4 compatible',
description: 'Transaction pooler connections are IPv4 proxied for free.',
}}
notice="Transaction pooler does not support prepared statements"
notice={['Does not support PREPARE statements']}
parameters={[
// prettier-ignore
{ ...CONNECTION_PARAMETERS.host, value: `${projectRef}.pooler.supabase.${poolerTld}` },
@@ -369,13 +371,23 @@ export const DatabaseConnectionString = () => {
{ ...CONNECTION_PARAMETERS.pool_mode, value: 'transaction', description: 'Each transaction uses a different connection' },
]}
/>
<Admonition
type="warning"
title="Highly recommended to not use Session Pooler"
className="[&>div]:gap-0 px-8 [&>svg]:left-7 border-0 border-b rounded-none border-border-muted !py-4 mb-0"
>
<p className="text-sm text-foreground-lighter !mb-0">
If you are using Session Pooler, we recommend switching to Direct Connection.
</p>
</Admonition>
<ConnectionPanel
contentType={contentType}
lang={lang}
type="session"
title="Session pooler"
fileTitle={fileTitle}
description="Better suited for applications with longer-running sessions that need persistent state or session-based features."
description="Only recommended as an alternative to Direct Connection, when connecting via a IPv4 network."
connectionString={connectionStrings['pooler'][selectedTab].replace('6543', '5432')}
onCopy={() => handleCopy(selectedTab)}
ipv4Status={{
@@ -154,7 +154,7 @@ const RECT_WIDTH = ICON_WIDTH * 0.67 // ~67% of total width
const CIRCLE_Y = ICON_HEIGHT * 0.13 // 13% from top
const CIRCLE_SPACING = ICON_WIDTH * 0.25 // 25% of width
const CIRCLE_START_X = ICON_WIDTH * 0.25 // 25% from left
const CIRCLE_RADIUS = ICON_WIDTH * 0.038 // ~3.8% of width
const CIRCLE_RADIUS = ICON_WIDTH * 0.055 // ~3.8% of width
// Static circle for SessionIcon
const ConnectionDot = ({ index, isActive }: { index: number; isActive: boolean }) => (
@@ -385,3 +385,102 @@ export const SessionIcon = () => {
</div>
)
}
export const DirectConnectionIcon = () => {
const [dots, setDots] = useState([false, false, false])
const [lines, setLines] = useState([false, false, false])
useEffect(() => {
// Function to animate a single dot
const animateDot = (index: number) => {
setDots((prev) => {
const newState = [...prev]
newState[index] = true
return newState
})
setLines((prev) => {
const newState = [...prev]
newState[index] = true
return newState
})
// Clear after 2.5s
setTimeout(() => {
setDots((prev) => {
const newState = [...prev]
newState[index] = false
return newState
})
setLines((prev) => {
const newState = [...prev]
newState[index] = false
return newState
})
}, 2500)
}
// Initial staggered animation
// Start initial animations immediately with slight delays
setTimeout(() => animateDot(0), 100)
setTimeout(() => animateDot(1), 1500)
setTimeout(() => animateDot(2), 3000)
// Set up intervals for continuous animation
const intervals = [0, 1, 2].map((index) =>
setInterval(() => animateDot(index), Math.random() * 3000 + 8000)
)
return () => intervals.forEach(clearInterval)
}, [])
return (
<div style={{ position: 'relative', width: ICON_WIDTH, height: ICON_HEIGHT }}>
<svg width={ICON_WIDTH} height={ICON_HEIGHT} viewBox={`0 0 ${ICON_WIDTH} ${ICON_HEIGHT}`}>
{[0, 1, 2].map((index) => (
<React.Fragment key={index}>
<AnimatePresence>
{dots[index] && (
<motion.circle
cx={CIRCLE_START_X + index * CIRCLE_SPACING}
cy={CIRCLE_Y}
r={CIRCLE_RADIUS}
className={'fill-foreground'}
initial={{
scale: 0,
x: [-8, -5, -2][index],
y: -10,
}}
animate={{
scale: 1,
x: 0,
y: 0,
}}
exit={{
scale: 0,
x: [8, 5, 2][index],
y: -10,
}}
transition={{
type: 'spring',
stiffness: 500,
damping: 30,
}}
/>
)}
</AnimatePresence>
</React.Fragment>
))}
<BottomRect isActive={lines.some((state) => state)} />
</svg>
{[0, 1, 2].map((index) => (
<FlowingLine
key={index}
x={CIRCLE_START_X + index * CIRCLE_SPACING}
y1={TOP_LINE_START}
y2={BOTTOM_LINE_END}
isActive={lines[index]}
/>
))}
</div>
)
}