CreateSession creates a new DuckDB session for the given username. secretStatements are the user's persistent secrets to replay (shared-warm mode only); replay failures come back as warnings — logged on the worker and again by the control plane's session manager, never failing the session — rather t
(username, memoryLimit string, threads int, secretStatements []string)
| 960 | } |
| 961 | |
| 962 | slog.Info("Starting DuckDB service", "network", network, "addr", addr) |
| 963 | } |
| 964 | |
| 965 | // Handle graceful shutdown |
| 966 | sigChan := make(chan os.Signal, 1) |
| 967 | signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) |
| 968 | |
| 969 | go func() { |
| 970 | <-sigChan |
| 971 | slog.Info("Draining DuckDB service before shutdown...") |
| 972 | svc.BeginDrain() |
| 973 | ctx, cancel := context.WithTimeout(context.Background(), workerShutdownDrainTime) |
| 974 | if !svc.WaitForDrain(ctx) { |
| 975 | slog.Warn("DuckDB service drain timed out before shutdown.", "timeout", workerShutdownDrainTime) |
| 976 | cancel() |
| 977 | // Close first so teardown WARNs land in the batch, then flush. |
| 978 | svc.CloseAll() |
| 979 | cliboot.FlushLogging() |
| 980 | os.Exit(0) |
| 981 | } |
| 982 | cancel() |
| 983 | slog.Info("Shutting down DuckDB service...") |
| 984 | svc.Shutdown() |
| 985 | cliboot.FlushLogging() |
| 986 | os.Exit(0) |
| 987 | }() |
| 988 | |
| 989 | if err := svc.Serve(listener); err != nil { |
| 990 | slog.Error("DuckDB service error", "error", err) |
| 991 | os.Exit(1) |
| 992 | } |
| 993 | } |
| 994 | |
| 995 | // Serve starts serving on the given listener. |
| 996 | func (svc *DuckDBService) Serve(listener net.Listener) error { |
| 997 | handler := NewFlightSQLHandler(svc.pool) |
| 998 | |
| 999 | opts, err := flightServerOptions(svc.cfg, listener) |
| 1000 | if err != nil { |
| 1001 | return err |
| 1002 | } |
| 1003 | |
| 1004 | // Wrap the flightsql server with custom action handling. |
| 1005 | // flightsql.NewFlightServer routes standard Flight SQL actions but rejects |
| 1006 | // custom action types. Our wrapper intercepts custom actions (CreateSession, |
| 1007 | // DestroySession, HealthCheck) before falling through to the standard router. |
| 1008 | flightSqlSrv := flightsql.NewFlightServer(handler) |
| 1009 | customSrv := &customActionServer{FlightServer: flightSqlSrv, handler: handler} |
| 1010 | |
| 1011 | svc.flightSrv = flight.NewServerWithMiddleware(nil, opts...) |
| 1012 | svc.flightSrv.RegisterFlightService(customSrv) |
| 1013 | svc.flightSrv.InitListener(listener) |
| 1014 | return svc.flightSrv.Serve() |
| 1015 | } |
| 1016 | |
| 1017 | func flightServerOptions(cfg ServiceConfig, listener net.Listener) ([]grpc.ServerOption, error) { |
| 1018 | opts := []grpc.ServerOption{ |
| 1019 | grpc.MaxRecvMsgSize(flightclient.MaxGRPCMessageSize), |