diff --git a/app/Jobs/PushServerUpdateJob.php b/app/Jobs/PushServerUpdateJob.php index 37c73f168..62e98934e 100644 --- a/app/Jobs/PushServerUpdateJob.php +++ b/app/Jobs/PushServerUpdateJob.php @@ -101,6 +101,8 @@ class PushServerUpdateJob implements ShouldBeEncrypted, ShouldQueue, Silenced public bool $foundLogDrainContainer = false; + private ?array $cachedDestinationIds = null; + public function middleware(): array { return [(new WithoutOverlapping('push-server-update-'.$this->server->uuid))->expireAfter(30)->dontRelease()]; @@ -156,6 +158,10 @@ public function handle() $this->serviceApplicationsById ??= collect(); $this->serviceDatabasesById ??= collect(); + // Eager-load relations the job touches repeatedly to avoid lazy-load queries + // (settings: disk threshold, isProxyShouldRun, isLogDrainEnabled; team: notifications). + $this->server->loadMissing(['settings', 'team']); + // TODO: Swarm is not supported yet if (! $this->data) { throw new \Exception('No data provided'); @@ -327,21 +333,23 @@ private function loadApplications(): Collection { [$standaloneDockerIds, $swarmDockerIds] = $this->serverDestinationIds(); - $applications = Application::withoutGlobalScope('withRelations') - ->select([ - 'id', - 'uuid', - 'name', - 'status', - 'build_pack', - 'docker_compose_raw', - 'destination_id', - 'destination_type', - 'last_online_at', - ]) - ->withCount('additional_servers') - ->where(fn ($query) => $this->scopeDestination($query, $standaloneDockerIds, $swarmDockerIds)) - ->get(); + $applications = ($standaloneDockerIds->isNotEmpty() || $swarmDockerIds->isNotEmpty()) + ? Application::withoutGlobalScope('withRelations') + ->select([ + 'id', + 'uuid', + 'name', + 'status', + 'build_pack', + 'docker_compose_raw', + 'destination_id', + 'destination_type', + 'last_online_at', + ]) + ->withCount('additional_servers') + ->where(fn ($query) => $this->scopeDestination($query, $standaloneDockerIds, $swarmDockerIds)) + ->get() + : collect(); $additionalApplicationIds = DB::table('additional_destinations') ->where('server_id', $this->server->id) @@ -409,6 +417,9 @@ private function loadServices(): Collection private function loadDatabases(): Collection { [$standaloneDockerIds, $swarmDockerIds] = $this->serverDestinationIds(); + if ($standaloneDockerIds->isEmpty() && $swarmDockerIds->isEmpty()) { + return collect(); + } $databaseColumns = [ 'id', 'uuid', @@ -442,7 +453,11 @@ private function loadDatabases(): Collection private function serverDestinationIds(): array { - return [ + if ($this->cachedDestinationIds !== null) { + return $this->cachedDestinationIds; + } + + return $this->cachedDestinationIds = [ StandaloneDocker::where('server_id', $this->server->id)->pluck('id'), SwarmDocker::where('server_id', $this->server->id)->pluck('id'), ]; diff --git a/database/migrations/2026_05_27_000000_add_push_server_update_job_indexes.php b/database/migrations/2026_05_27_000000_add_push_server_update_job_indexes.php new file mode 100644 index 000000000..e74929147 --- /dev/null +++ b/database/migrations/2026_05_27_000000_add_push_server_update_job_indexes.php @@ -0,0 +1,27 @@ + >(while read line; do echo "$(timestamp) [TERMINAL] $line"; done) 2>&1 & +start_logger() { + prefix="$1" + fifo_path="$2" + + while read -r line; do + echo "$(date '+%Y-%m-%d %H:%M:%S') [$prefix] $line" + done < "$fifo_path" & +} + +cleanup() { + rm -f "$TERMINAL_LOG_FIFO" "$SOKETI_LOG_FIFO" +} + +TERMINAL_LOG_FIFO="/tmp/coolify-terminal-log.$$" +SOKETI_LOG_FIFO="/tmp/coolify-soketi-log.$$" + +rm -f "$TERMINAL_LOG_FIFO" "$SOKETI_LOG_FIFO" +mkfifo "$TERMINAL_LOG_FIFO" "$SOKETI_LOG_FIFO" + +trap cleanup EXIT + +log "Starting realtime container" +log "WATCH_MODE=${WATCH_MODE:-off}" +log "SOKETI_DEBUG=${SOKETI_DEBUG:-unset}" +log "NODE_OPTIONS=${NODE_OPTIONS:-unset}" + +start_logger "TERMINAL" "$TERMINAL_LOG_FIFO" +TERMINAL_LOGGER_PID=$! + +start_logger "SOKETI" "$SOKETI_LOG_FIFO" +SOKETI_LOGGER_PID=$! + +node $WATCH_MODE /terminal/terminal-server.js > "$TERMINAL_LOG_FIFO" 2>&1 & TERMINAL_PID=$! -# Start the Soketi process in the background with logging -node /app/bin/server.js start > >(while read line; do echo "$(timestamp) [SOKETI] $line"; done) 2>&1 & +log "Terminal server started pid=$TERMINAL_PID logger_pid=$TERMINAL_LOGGER_PID" + +node /app/bin/server.js start > "$SOKETI_LOG_FIFO" 2>&1 & SOKETI_PID=$! -# Function to forward signals to child processes +log "Soketi started pid=$SOKETI_PID logger_pid=$SOKETI_LOGGER_PID" + forward_signal() { - kill -$1 $TERMINAL_PID $SOKETI_PID + log "Forwarding signal $1 to terminal=$TERMINAL_PID soketi=$SOKETI_PID" + + kill -"$1" "$TERMINAL_PID" 2>/dev/null || true + kill -"$1" "$SOKETI_PID" 2>/dev/null || true } -# Forward SIGTERM to child processes trap 'forward_signal TERM' TERM +trap 'forward_signal INT' INT -# Wait for any process to exit -wait -n +while true; do + if ! kill -0 "$TERMINAL_PID" 2>/dev/null; then + wait "$TERMINAL_PID" + EXIT_CODE=$? -# Exit with status of process that exited first -exit $? + log "Terminal server exited code=$EXIT_CODE; stopping soketi pid=$SOKETI_PID" + + kill "$SOKETI_PID" 2>/dev/null || true + wait "$SOKETI_PID" 2>/dev/null || true + + exit "$EXIT_CODE" + fi + + if ! kill -0 "$SOKETI_PID" 2>/dev/null; then + wait "$SOKETI_PID" + EXIT_CODE=$? + + log "Soketi exited code=$EXIT_CODE; stopping terminal pid=$TERMINAL_PID" + + kill "$TERMINAL_PID" 2>/dev/null || true + wait "$TERMINAL_PID" 2>/dev/null || true + + exit "$EXIT_CODE" + fi + + sleep 1 +done