Add Neo4j memory tuning config and query result limits (v0.43.0)
Some checks failed
Go / build-and-release (push) Has been cancelled

- Add Neo4j driver config options for memory management:
  - ORLY_NEO4J_MAX_CONN_POOL (default: 25) - connection pool size
  - ORLY_NEO4J_FETCH_SIZE (default: 1000) - records per batch
  - ORLY_NEO4J_MAX_TX_RETRY_SEC (default: 30) - transaction retry timeout
  - ORLY_NEO4J_QUERY_RESULT_LIMIT (default: 10000) - max results per query
- Apply driver settings when creating Neo4j connection (pool size, fetch size, retry time)
- Enforce query result limit as safety cap on all Cypher queries
- Fix QueryForSerials and QueryForIds to preserve LIMIT clauses
- Add comprehensive memory tuning documentation with sizing guidelines
- Add NIP-46 signer-based authentication for bunker connections
- Update go.mod with new dependencies

Files modified:
- app/config/config.go: Add Neo4j driver tuning config vars
- main.go: Pass new config values to database factory
- pkg/database/factory.go: Add Neo4j tuning fields to DatabaseConfig
- pkg/database/factory_wasm.go: Mirror factory.go changes for WASM
- pkg/neo4j/neo4j.go: Apply driver config, add getter methods
- pkg/neo4j/query-events.go: Enforce query result limit, fix LIMIT preservation
- docs/NEO4J_BACKEND.md: Add Memory Tuning section, update Docker example
- CLAUDE.md: Add Neo4j memory tuning quick reference
- app/handle-req.go: NIP-46 signer authentication
- app/publisher.go: HasActiveNIP46Signer check
- pkg/protocol/publish/publisher.go: NIP46SignerChecker interface
- go.mod: Add dependencies

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-29 02:18:05 +02:00
parent aef9e24e40
commit f22bf3f388
13 changed files with 412 additions and 49 deletions

View File

@@ -223,10 +223,25 @@ RETURN e.id AS id,
// Add ordering (most recent first)
orderClause := " ORDER BY e.created_at DESC"
// Add limit if specified
// Add limit - use the smaller of requested limit and configured max limit
// This prevents unbounded queries that could exhaust memory
limitClause := ""
requestedLimit := 0
if f.Limit != nil && *f.Limit > 0 {
params["limit"] = *f.Limit
requestedLimit = int(*f.Limit)
}
// Apply the configured query result limit as a safety cap
// If queryResultLimit is 0 (unlimited), only use the requested limit
effectiveLimit := requestedLimit
if n.queryResultLimit > 0 {
if effectiveLimit == 0 || effectiveLimit > n.queryResultLimit {
effectiveLimit = n.queryResultLimit
}
}
if effectiveLimit > 0 {
params["limit"] = effectiveLimit
limitClause = " LIMIT $limit"
}
@@ -358,11 +373,16 @@ func (n *N) QueryForSerials(c context.Context, f *filter.F) (
return nil, fmt.Errorf("invalid query structure")
}
// Rebuild query with serial-only return
// Rebuild query with serial-only return, preserving ORDER BY and LIMIT
cypher = cypherParts[0] + returnClause
if strings.Contains(cypherParts[1], "ORDER BY") {
orderPart := " ORDER BY" + strings.Split(cypherParts[1], "ORDER BY")[1]
cypher += orderPart
remainder := cypherParts[1]
if strings.Contains(remainder, "ORDER BY") {
orderAndLimit := " ORDER BY" + strings.Split(remainder, "ORDER BY")[1]
cypher += orderAndLimit
} else if strings.Contains(remainder, "LIMIT") {
// No ORDER BY but has LIMIT
limitPart := " LIMIT" + strings.Split(remainder, "LIMIT")[1]
cypher += limitPart
}
result, err := n.ExecuteRead(c, cypher, params)
@@ -417,10 +437,16 @@ func (n *N) QueryForIds(c context.Context, f *filter.F) (
return nil, fmt.Errorf("invalid query structure")
}
// Rebuild query preserving ORDER BY and LIMIT
cypher = cypherParts[0] + returnClause
if strings.Contains(cypherParts[1], "ORDER BY") {
orderPart := " ORDER BY" + strings.Split(cypherParts[1], "ORDER BY")[1]
cypher += orderPart
remainder := cypherParts[1]
if strings.Contains(remainder, "ORDER BY") {
orderAndLimit := " ORDER BY" + strings.Split(remainder, "ORDER BY")[1]
cypher += orderAndLimit
} else if strings.Contains(remainder, "LIMIT") {
// No ORDER BY but has LIMIT
limitPart := " LIMIT" + strings.Split(remainder, "LIMIT")[1]
cypher += limitPart
}
result, err := n.ExecuteRead(c, cypher, params)