docs: add LaunchDaemon architecture reference for M5Max128/M5Max48 collaboration
This commit is contained in:
421
docs_v1.0/DESIGN/LaunchDaemon_Config_M5Max128.md
Normal file
421
docs_v1.0/DESIGN/LaunchDaemon_Config_M5Max128.md
Normal file
@@ -0,0 +1,421 @@
|
||||
---
|
||||
title: LaunchDaemon Architecture (M5Max128 Reference)
|
||||
version: 1.0
|
||||
date: 2026-05-27
|
||||
author: M5Max128
|
||||
status: reference
|
||||
---
|
||||
|
||||
# LaunchDaemon Architecture Reference
|
||||
|
||||
> **Scope**: M5Max128 local configuration (resource-managed binaries)
|
||||
> **Note**: M5Max48 uses build-from-source approach via start_momentry.sh. Both approaches are valid and independent.
|
||||
|
||||
## Overview
|
||||
|
||||
| Machine | Approach | Status |
|
||||
|---------|----------|--------|
|
||||
| M5Max128 | LaunchDaemon + resource binaries | Reference document |
|
||||
| M5Max48 | start_momentry.sh + build from source | Main branch |
|
||||
|
||||
## Architecture Principles
|
||||
|
||||
```
|
||||
/Library/LaunchDaemons/ (system-level, boot before login)
|
||||
├── com.momentry.postgresql.plist (P1, no dependency)
|
||||
├── com.momentry.redis.plist (P1, no dependency)
|
||||
├── com.momentry.qdrant.plist (P2, no dependency)
|
||||
├── com.momentry.mongodb.plist (P2, no dependency)
|
||||
└── com.momentry.gitea.plist (P3, depends on PostgreSQL)
|
||||
|
||||
Experimental services:
|
||||
└── com.momentry.startup.plist (LLM, Embedding, Playground, etc.)
|
||||
```
|
||||
|
||||
## Key Design Points
|
||||
|
||||
### 1. Binary Location
|
||||
|
||||
All binaries are resource-managed under `/Users/accusys/momentry_resources/bin/`:
|
||||
|
||||
| Service | Binary Path |
|
||||
|---------|-------------|
|
||||
| PostgreSQL | `/Users/accusys/pgsql/18.3/bin/postgres` |
|
||||
| Redis | `/Users/accusys/momentry_resources/bin/redis-server` |
|
||||
| Qdrant | `/Users/accusys/momentry_resources/bin/qdrant` |
|
||||
| MongoDB | `/Users/accusys/momentry_resources/bin/mongod` |
|
||||
| Gitea | `/Users/accusys/momentry_resources/bin/gitea` |
|
||||
|
||||
### 2. Root Boot → User Execution
|
||||
|
||||
LaunchDaemons run at boot (root), but use `UserName` key to switch to user:
|
||||
|
||||
```xml
|
||||
<key>UserName</key>
|
||||
<string>accusys</string>
|
||||
```
|
||||
|
||||
### 3. Unified Log Path
|
||||
|
||||
All logs go to `/Users/accusys/momentry/logs/`:
|
||||
|
||||
```xml
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/accusys/momentry/logs/<service>.log</string>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/accusys/momentry/logs/<service>.error.log</string>
|
||||
```
|
||||
|
||||
## Plist Templates
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.momentry.postgresql</string>
|
||||
|
||||
<key>UserName</key>
|
||||
<string>accusys</string>
|
||||
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/accusys/momentry/var/postgresql</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/accusys/pgsql/18.3/bin/postgres</string>
|
||||
<string>-D</string>
|
||||
<string>/Users/accusys/momentry/var/postgresql</string>
|
||||
</array>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/accusys/momentry/logs/postgresql.log</string>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/accusys/momentry/logs/postgresql.error.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
### Redis (ACL Authentication)
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.momentry.redis</string>
|
||||
|
||||
<key>UserName</key>
|
||||
<string>accusys</string>
|
||||
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/accusys/momentry/var/redis</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/accusys/momentry_resources/bin/redis-server</string>
|
||||
<string>--port</string>
|
||||
<string>6379</string>
|
||||
<string>--bind</string>
|
||||
<string>0.0.0.0</string>
|
||||
<string>--aclfile</string>
|
||||
<string>/Users/accusys/momentry/etc/redis/users.acl</string>
|
||||
<string>--dir</string>
|
||||
<string>/Users/accusys/momentry/var/redis</string>
|
||||
<string>--logfile</string>
|
||||
<string>/Users/accusys/momentry/logs/redis.log</string>
|
||||
</array>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/accusys/momentry/logs/redis.log</string>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/accusys/momentry/logs/redis.error.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
### Redis ACL File
|
||||
|
||||
Location: `/Users/accusys/momentry/etc/redis/users.acl`
|
||||
|
||||
```
|
||||
user default on sanitize-payload ~* &* +@all >accusys
|
||||
user accusys on sanitize-payload ~* &* +@all >accusys
|
||||
```
|
||||
|
||||
**Redis 8.x Authentication**:
|
||||
```bash
|
||||
# Old (deprecated): redis-cli -a accusys ping
|
||||
# New (recommended): redis-cli --user default --pass accusys ping
|
||||
```
|
||||
|
||||
### Qdrant
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.momentry.qdrant</string>
|
||||
|
||||
<key>UserName</key>
|
||||
<string>accusys</string>
|
||||
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/accusys/momentry/var/qdrant/</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/accusys/momentry_resources/bin/qdrant</string>
|
||||
</array>
|
||||
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>QDRANT__STORAGE__STORAGE_PATH</key>
|
||||
<string>/Users/accusys/momentry/var/qdrant/</string>
|
||||
<key>QDRANT__SERVICE__HOST</key>
|
||||
<string>0.0.0.0</string>
|
||||
<key>QDRANT__SERVICE__HTTP_PORT</key>
|
||||
<string>6333</string>
|
||||
<key>HOME</key>
|
||||
<string>/Users/accusys</string>
|
||||
</dict>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/accusys/momentry/logs/qdrant.log</string>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/accusys/momentry/logs/qdrant.error.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
### MongoDB
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.momentry.mongodb</string>
|
||||
|
||||
<key>UserName</key>
|
||||
<string>accusys</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/accusys/momentry_resources/bin/mongod</string>
|
||||
<string>--dbpath</string>
|
||||
<string>/Users/accusys/momentry/var/mongodb</string>
|
||||
<string>--logpath</string>
|
||||
<string>/Users/accusys/momentry/logs/mongodb.log</string>
|
||||
<string>--port</string>
|
||||
<string>27017</string>
|
||||
<string>--bind_ip</string>
|
||||
<string>0.0.0.0</string>
|
||||
</array>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/accusys/momentry/logs/mongodb.log</string>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/accusys/momentry/logs/mongodb.error.log</string>
|
||||
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/accusys/momentry/var/mongodb</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
### Gitea (with Wrapper Script)
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>com.momentry.gitea</string>
|
||||
|
||||
<key>UserName</key>
|
||||
<string>accusys</string>
|
||||
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/accusys/momentry/var/gitea</string>
|
||||
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/Users/accusys/momentry_core/scripts/start_gitea.sh</string>
|
||||
</array>
|
||||
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>HOME</key>
|
||||
<string>/Users/accusys</string>
|
||||
<key>GITEA_WORK_DIR</key>
|
||||
<string>/Users/accusys/momentry/var/gitea</string>
|
||||
</dict>
|
||||
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>/Users/accusys/momentry/logs/gitea.log</string>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/Users/accusys/momentry/logs/gitea.error.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
## Wrapper Script: start_gitea.sh
|
||||
|
||||
Gitea depends on PostgreSQL. Wrapper script ensures PostgreSQL is ready:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
PG_BIN="/Users/accusys/pgsql/18.3/bin"
|
||||
GITEA_BIN="/Users/accusys/momentry_resources/bin/gitea"
|
||||
GITEA_CONFIG="/Users/accusys/momentry/etc/gitea/app.ini"
|
||||
|
||||
MAX_WAIT=60
|
||||
WAITED=0
|
||||
|
||||
# Wait for PostgreSQL
|
||||
while ! "$PG_BIN/pg_isready" -q 2>/dev/null; do
|
||||
if [ $WAITED -ge $MAX_WAIT ]; then
|
||||
echo "ERROR: PostgreSQL not ready after $MAX_WAIT seconds"
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
WAITED=$((WAITED + 2))
|
||||
done
|
||||
|
||||
# Start Gitea
|
||||
"$GITEA_BIN" web --config "$GITEA_CONFIG"
|
||||
```
|
||||
|
||||
## Install Script: install_launchdaemons.sh
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
PLIST_DIR="/Users/accusys/momentry_core/momentry_runtime/plist"
|
||||
DAEMON_DIR="/Library/LaunchDaemons"
|
||||
LOG_DIR="/Users/accusys/momentry/logs"
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
DAEMONS=(
|
||||
"com.momentry.postgresql"
|
||||
"com.momentry.redis"
|
||||
"com.momentry.qdrant"
|
||||
"com.momentry.mongodb"
|
||||
"com.momentry.gitea"
|
||||
)
|
||||
|
||||
for daemon in "${DAEMONS[@]}"; do
|
||||
plist_name="${daemon}.plist"
|
||||
src="${PLIST_DIR}/${plist_name}"
|
||||
dest="${DAEMON_DIR}/${plist_name}"
|
||||
|
||||
if launchctl list "$daemon" >/dev/null 2>&1; then
|
||||
sudo launchctl unload -w "$dest" 2>/dev/null
|
||||
fi
|
||||
|
||||
sudo cp "$src" "$dest"
|
||||
sudo chown root:wheel "$dest"
|
||||
sudo chmod 644 "$dest"
|
||||
sudo launchctl load -w "$dest"
|
||||
done
|
||||
```
|
||||
|
||||
## Comparison: M5Max128 vs M5Max48
|
||||
|
||||
| Aspect | M5Max128 | M5Max48 |
|
||||
|--------|----------|---------|
|
||||
| **Approach** | LaunchDaemon (system-level) | start_momentry.sh (user script) |
|
||||
| **Binaries** | Resource-managed (`momentry_resources/bin/`) | Build from source (`services/*/target/`) |
|
||||
| **PostgreSQL data** | `/Users/accusys/momentry/var/postgresql` | `/Users/accusys/pgsql/data` |
|
||||
| **Redis auth** | ACL file (`users.acl`) | `--requirepass` (deprecated) |
|
||||
| **LLM path** | Resource binary | `/Users/accusys/llama/bin/` |
|
||||
| **Gitea** | Independent LaunchDaemon | Not in startup script |
|
||||
| **MongoDB** | Independent LaunchDaemon | Not in startup script |
|
||||
|
||||
## Installation Steps (M5Max128)
|
||||
|
||||
```bash
|
||||
# 1. Ensure directories exist
|
||||
mkdir -p /Users/accusys/momentry/logs
|
||||
mkdir -p /Users/accusys/momentry/var/{postgresql,redis,qdrant,mongodb,gitea}
|
||||
|
||||
# 2. Install LaunchDaemons (requires sudo)
|
||||
sudo /Users/accusys/momentry_core/scripts/install_launchdaemons.sh
|
||||
|
||||
# 3. Verify services
|
||||
/Users/accusys/pgsql/18.3/bin/pg_isready
|
||||
/Users/accusys/momentry_resources/bin/redis-cli --user default --pass accusys ping
|
||||
curl http://localhost:6333/healthz
|
||||
curl http://localhost:3000/
|
||||
|
||||
# 4. Reboot test
|
||||
sudo reboot
|
||||
|
||||
# 5. Post-reboot verification
|
||||
launchctl list | grep com.momentry
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
1. **Independence**: M5Max128's LaunchDaemons do not conflict with M5Max48's startup script. Each machine has its own approach.
|
||||
|
||||
2. **Resource Management**: M5Max128 uses pre-built binaries from `momentry_resources/bin/`, avoiding build dependencies.
|
||||
|
||||
3. **Redis ACL**: Redis 8.x uses ACL authentication, not `--requirepass`. This is the modern approach.
|
||||
|
||||
4. **Gitea Wrapper**: Essential because Gitea depends on PostgreSQL. The wrapper ensures PostgreSQL is ready before starting Gitea.
|
||||
|
||||
---
|
||||
|
||||
## Version History
|
||||
|
||||
| Version | Date | Author | Changes |
|
||||
|---------|------|--------|---------|
|
||||
| 1.0 | 2026-05-27 | M5Max128 | Initial reference document |
|
||||
Reference in New Issue
Block a user