main.go raw
1 // orly-db-neo4j is a standalone gRPC database server using the Neo4j backend.
2 package main
3
4 import (
5 "context"
6 "os"
7 "time"
8
9 "go-simpler.org/env"
10 "next.orly.dev/pkg/lol"
11 "next.orly.dev/pkg/lol/chk"
12 "next.orly.dev/pkg/lol/log"
13
14 "next.orly.dev/pkg/database"
15 "next.orly.dev/pkg/database/server"
16
17 // Import neo4j to register the factory
18 _ "next.orly.dev/pkg/neo4j"
19 )
20
21 // Config holds the database server configuration.
22 type Config struct {
23 // Listen is the gRPC server listen address
24 Listen string `env:"ORLY_DB_LISTEN" default:"127.0.0.1:50051" usage:"gRPC server listen address"`
25
26 // LogLevel is the logging level
27 LogLevel string `env:"ORLY_DB_LOG_LEVEL" default:"info" usage:"log level (trace, debug, info, warn, error)"`
28
29 // DataDir is required by the database layer for metadata storage
30 DataDir string `env:"ORLY_DATA_DIR" default:"/tmp/orly-neo4j" usage:"data directory for metadata"`
31
32 // Neo4j configuration
33 Neo4jURI string `env:"ORLY_NEO4J_URI" default:"bolt://localhost:7687" usage:"Neo4j connection URI"`
34 Neo4jUser string `env:"ORLY_NEO4J_USER" default:"neo4j" usage:"Neo4j username"`
35 Neo4jPassword string `env:"ORLY_NEO4J_PASSWORD" usage:"Neo4j password"`
36
37 // Neo4j driver tuning
38 Neo4jMaxConnPoolSize int `env:"ORLY_NEO4J_MAX_CONN_POOL" default:"25" usage:"max connection pool size"`
39 Neo4jFetchSize int `env:"ORLY_NEO4J_FETCH_SIZE" default:"1000" usage:"max records per fetch batch"`
40 Neo4jMaxTxRetrySeconds int `env:"ORLY_NEO4J_MAX_TX_RETRY_SEC" default:"30" usage:"max transaction retry time"`
41 Neo4jQueryResultLimit int `env:"ORLY_NEO4J_QUERY_RESULT_LIMIT" default:"10000" usage:"max results per query (0=unlimited)"`
42
43 // Query cache configuration (for the gRPC server)
44 QueryCacheSizeMB int `env:"ORLY_DB_QUERY_CACHE_SIZE_MB" default:"256" usage:"query cache size in MB"`
45 QueryCacheMaxAge time.Duration `env:"ORLY_DB_QUERY_CACHE_MAX_AGE" default:"5m" usage:"query cache max age"`
46 QueryCacheDisabled bool `env:"ORLY_DB_QUERY_CACHE_DISABLED" default:"false" usage:"disable query cache"`
47
48 // gRPC server configuration
49 StreamBatchSize int `env:"ORLY_DB_STREAM_BATCH_SIZE" default:"100" usage:"events per stream batch"`
50 }
51
52 func main() {
53 cfg := loadConfig()
54
55 // Set log level
56 lol.SetLogLevel(cfg.LogLevel)
57 log.I.F("orly-db-neo4j starting with log level: %s", cfg.LogLevel)
58
59 ctx, cancel := context.WithCancel(context.Background())
60 defer cancel()
61
62 // Create database configuration
63 dbCfg := &database.DatabaseConfig{
64 DataDir: cfg.DataDir,
65 LogLevel: cfg.LogLevel,
66 Neo4jURI: cfg.Neo4jURI,
67 Neo4jUser: cfg.Neo4jUser,
68 Neo4jPassword: cfg.Neo4jPassword,
69 Neo4jMaxConnPoolSize: cfg.Neo4jMaxConnPoolSize,
70 Neo4jFetchSize: cfg.Neo4jFetchSize,
71 Neo4jMaxTxRetrySeconds: cfg.Neo4jMaxTxRetrySeconds,
72 Neo4jQueryResultLimit: cfg.Neo4jQueryResultLimit,
73 QueryCacheSizeMB: cfg.QueryCacheSizeMB,
74 QueryCacheMaxAge: cfg.QueryCacheMaxAge,
75 QueryCacheDisabled: cfg.QueryCacheDisabled,
76 }
77
78 // Initialize Neo4j database via factory
79 log.I.F("connecting to Neo4j at %s", cfg.Neo4jURI)
80 db, err := database.NewDatabaseWithConfig(ctx, cancel, "neo4j", dbCfg)
81 if chk.E(err) {
82 log.E.F("failed to initialize Neo4j database: %v", err)
83 os.Exit(1)
84 }
85
86 // Wait for database to be ready
87 log.I.F("waiting for database to be ready...")
88 <-db.Ready()
89 log.I.F("database ready")
90
91 // Create and start gRPC server
92 serverCfg := &server.Config{
93 Listen: cfg.Listen,
94 LogLevel: cfg.LogLevel,
95 StreamBatchSize: cfg.StreamBatchSize,
96 }
97
98 srv := server.New(db, serverCfg)
99 if err := srv.ListenAndServe(ctx, cancel); err != nil {
100 log.E.F("gRPC server error: %v", err)
101 }
102 }
103
104 func loadConfig() *Config {
105 cfg := &Config{}
106 if err := env.Load(cfg, nil); chk.E(err) {
107 log.E.F("failed to load config: %v", err)
108 os.Exit(1)
109 }
110
111 return cfg
112 }
113