mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-06 20:15:17 +02:00
fix: made migartion idempotent and fixed docker-compose
This commit is contained in:
parent
32b8bb33f9
commit
35392c8e62
4 changed files with 65 additions and 7 deletions
|
|
@ -8,10 +8,13 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
- ./scripts/docker/postgresql.conf:/etc/postgresql/postgresql.conf:ro
|
- ./scripts/docker/postgresql.conf:/etc/postgresql/postgresql.conf:ro
|
||||||
|
- ./scripts/docker/init-electric-user.sh:/docker-entrypoint-initdb.d/init-electric-user.sh:ro
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=${POSTGRES_USER:-postgres}
|
- POSTGRES_USER=${POSTGRES_USER:-postgres}
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres}
|
||||||
- POSTGRES_DB=${POSTGRES_DB:-surfsense}
|
- POSTGRES_DB=${POSTGRES_DB:-surfsense}
|
||||||
|
- ELECTRIC_DB_USER=${ELECTRIC_DB_USER:-electric}
|
||||||
|
- ELECTRIC_DB_PASSWORD=${ELECTRIC_DB_PASSWORD:-electric_password}
|
||||||
command: postgres -c config_file=/etc/postgresql/postgresql.conf
|
command: postgres -c config_file=/etc/postgresql/postgresql.conf
|
||||||
|
|
||||||
pgadmin:
|
pgadmin:
|
||||||
|
|
@ -123,6 +126,8 @@ services:
|
||||||
- ELECTRIC_INSECURE=true
|
- ELECTRIC_INSECURE=true
|
||||||
- ELECTRIC_WRITE_TO_PG_MODE=direct
|
- ELECTRIC_WRITE_TO_PG_MODE=direct
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
# depends_on:
|
||||||
|
# - db
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3000/v1/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:3000/v1/health"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
|
|
|
||||||
48
scripts/docker/init-electric-user.sh
Executable file
48
scripts/docker/init-electric-user.sh
Executable file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# ============================================================================
|
||||||
|
# Electric SQL User Initialization Script (Docker deployments)
|
||||||
|
# ============================================================================
|
||||||
|
# Creates the Electric SQL replication user for Docker deployments.
|
||||||
|
#
|
||||||
|
# For local PostgreSQL users (non-Docker), this is handled by Alembic
|
||||||
|
# migration 66 (66_add_notifications_table_and_electric_replication.py).
|
||||||
|
#
|
||||||
|
# Both approaches are idempotent (use IF NOT EXISTS), so running both
|
||||||
|
# will not cause conflicts.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Use environment variables with defaults
|
||||||
|
ELECTRIC_DB_USER="${ELECTRIC_DB_USER:-electric}"
|
||||||
|
ELECTRIC_DB_PASSWORD="${ELECTRIC_DB_PASSWORD:-electric_password}"
|
||||||
|
|
||||||
|
echo "Creating Electric SQL replication user: $ELECTRIC_DB_USER"
|
||||||
|
|
||||||
|
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT FROM pg_user WHERE usename = '$ELECTRIC_DB_USER') THEN
|
||||||
|
CREATE USER $ELECTRIC_DB_USER WITH REPLICATION PASSWORD '$ELECTRIC_DB_PASSWORD';
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
|
||||||
|
GRANT CONNECT ON DATABASE $POSTGRES_DB TO $ELECTRIC_DB_USER;
|
||||||
|
GRANT USAGE ON SCHEMA public TO $ELECTRIC_DB_USER;
|
||||||
|
GRANT SELECT ON ALL TABLES IN SCHEMA public TO $ELECTRIC_DB_USER;
|
||||||
|
GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO $ELECTRIC_DB_USER;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO $ELECTRIC_DB_USER;
|
||||||
|
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON SEQUENCES TO $ELECTRIC_DB_USER;
|
||||||
|
|
||||||
|
-- Create the publication for Electric SQL (if not exists)
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT FROM pg_publication WHERE pubname = 'electric_publication_default') THEN
|
||||||
|
CREATE PUBLICATION electric_publication_default;
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
EOSQL
|
||||||
|
|
||||||
|
echo "Electric SQL user '$ELECTRIC_DB_USER' and publication created successfully"
|
||||||
|
|
@ -6,6 +6,11 @@ Revises: 65
|
||||||
Creates notifications table and sets up Electric SQL replication
|
Creates notifications table and sets up Electric SQL replication
|
||||||
(user, publication, REPLICA IDENTITY FULL) for notifications,
|
(user, publication, REPLICA IDENTITY FULL) for notifications,
|
||||||
search_source_connectors, and documents tables.
|
search_source_connectors, and documents tables.
|
||||||
|
|
||||||
|
NOTE: Electric SQL user creation is idempotent (uses IF NOT EXISTS).
|
||||||
|
- Docker deployments: user is pre-created by scripts/docker/init-electric-user.sh
|
||||||
|
- Local PostgreSQL: user is created here during migration
|
||||||
|
Both approaches are safe to run together without conflicts as this migraiton is idempotent
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
|
@ -46,11 +51,11 @@ def upgrade() -> None:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create indexes
|
# Create indexes (using IF NOT EXISTS for idempotency)
|
||||||
op.create_index("ix_notifications_user_id", "notifications", ["user_id"])
|
op.execute("CREATE INDEX IF NOT EXISTS ix_notifications_user_id ON notifications (user_id);")
|
||||||
op.create_index("ix_notifications_read", "notifications", ["read"])
|
op.execute("CREATE INDEX IF NOT EXISTS ix_notifications_read ON notifications (read);")
|
||||||
op.create_index("ix_notifications_created_at", "notifications", ["created_at"])
|
op.execute("CREATE INDEX IF NOT EXISTS ix_notifications_created_at ON notifications (created_at);")
|
||||||
op.create_index("ix_notifications_user_read", "notifications", ["user_id", "read"])
|
op.execute("CREATE INDEX IF NOT EXISTS ix_notifications_user_read ON notifications (user_id, read);")
|
||||||
|
|
||||||
# =====================================================
|
# =====================================================
|
||||||
# Electric SQL Setup - User and Publication
|
# Electric SQL Setup - User and Publication
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ export function NotificationPopup({
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case "in_progress":
|
case "in_progress":
|
||||||
return <Loader2 className="h-4 w-4 text-white animate-spin" />;
|
return <Loader2 className="h-4 w-4 text-foreground animate-spin" />;
|
||||||
case "completed":
|
case "completed":
|
||||||
return <CheckCircle2 className="h-4 w-4 text-green-500" />;
|
return <CheckCircle2 className="h-4 w-4 text-green-500" />;
|
||||||
case "failed":
|
case "failed":
|
||||||
|
|
@ -73,7 +73,7 @@ export function NotificationPopup({
|
||||||
<ScrollArea className="h-[400px]">
|
<ScrollArea className="h-[400px]">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div className="flex items-center justify-center py-8">
|
<div className="flex items-center justify-center py-8">
|
||||||
<Loader2 className="h-5 w-5 animate-spin text-white" />
|
<Loader2 className="h-5 w-5 animate-spin text-foreground" />
|
||||||
</div>
|
</div>
|
||||||
) : notifications.length === 0 ? (
|
) : notifications.length === 0 ? (
|
||||||
<div className="flex flex-col items-center justify-center py-8 px-4 text-center">
|
<div className="flex flex-col items-center justify-center py-8 px-4 text-center">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue