Skip to content

Commit 0f36565

Browse files
andyclaude
andcommitted
Merge wip/233-two-sessions: ending one session never stops the data server or broker while another session or a job store uses them; no crash when they disappear (#233)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y1pWhDKvhakdnjg3taYGxM
2 parents cfdaa6b + 63ba4c6 commit 0f36565

15 files changed

Lines changed: 704 additions & 76 deletions

File tree

‎docs/claude/services/the-gateway-window-no-longer-appears.md‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ type: map
33
title: "The Gateway window no longer appears"
44
area: services
55
section: "The Gateway window and session end"
6-
paths: ["~/.ECCE/mosquitto.server"]
7-
issues: [93, 97, 185, 191]
6+
paths: ["~/.ECCE/mosquitto.server", "packaging/dataserver/ecce-dataserver-stop", "packaging/gateway/ecce-gateway-reap", "src/apps/organizer/CalcMgr.C", "src/apps/gateway/Gateway.C"]
7+
issues: [93, 97, 185, 191, 233]
88
---
99
**The Gateway window no longer appears** (#93, 2026-09-22). `ecce`
1010
starts the services and opens the **Organizer** directly, which is now
@@ -26,4 +26,10 @@ SharedBroker` (mode 3, a systemd service no user can stop, not even
2626
with Quit and Stop Server), or `~/.ECCE/mosquitto.server` (`ecce-remote-
2727
setup --server`; mode 2, stopped only by that account's Quit and Stop
2828
Server). The per-user broker is `mosquitto` on a Unix socket (#213). The data server is
29-
stopped only by Quit and Stop Server, in every mode (#97).
29+
stopped only by Quit and Stop Server, in every mode (#97). **Quit and
30+
Stop Server stops nothing while another session of the account (any
31+
display) or a job is running** (#233): the Quit dialogs do not offer it
32+
then (`SessionLease::othersUsingServices`), and `ecce-dataserver-stop
33+
--if-unused` and `ecce-gateway-reap --stop` refuse
34+
(`ecce_others_using_services`). Without that, the second of two `ecce`
35+
on one display took the first one's broker and data server down.

‎include/util/SessionLease.H‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ std::vector<Holder> live(const std::string& statedir,
4040
bool useLease();
4141
bool useProc();
4242

43+
// The running ECCE programs that still use this account's data server
44+
// and broker, apart from this process's session: every program of another
45+
// session of this state directory (on any display, or with no id), and a
46+
// job store or job master of any session, since a job reports through
47+
// both. Holder::key is "" for a program without a session id. The same
48+
// rule as ecce_others_using_services in ecce-session-lib.sh.
49+
std::vector<Holder> othersUsingServices();
50+
4351
} // namespace SessionLease
4452

4553
#endif

‎packaging/dataserver/ecce-dataserver-stop‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,34 @@
11
#!/bin/bash
22
# ecce-dataserver-stop: stop the per-user data server started by
33
# ecce-dataserver-start.
4+
#
5+
# ecce-dataserver-stop --if-unused as a session's Quit and Stop Server
6+
# runs it: refuse (status 3) while another ECCE session of this
7+
# account, on any display, or a running job still uses the server.
48

59
set -u
610

11+
ECCE_HOME="${ECCE_HOME:-/opt/ecce}"
712
ECCE_REALUSERHOME="${ECCE_REALUSERHOME:-$HOME}"
813
STATEDIR="$ECCE_REALUSERHOME/.ECCE/dataserver"
914
CONF="$STATEDIR/httpd.conf"
1015
PIDFILE="$STATEDIR/logs/httpd.pid"
1116

17+
if [ "${1:-}" = --if-unused ]; then
18+
_lib="$(dirname "$(readlink -f "$0")")/ecce-session-lib.sh"
19+
[ -r "$_lib" ] || _lib="$ECCE_HOME/bin/ecce-session-lib.sh"
20+
if ! . "$_lib"; then
21+
echo "ecce-dataserver-stop: cannot read $_lib -- data server left running" >&2
22+
exit 3
23+
fi
24+
others="$(STATEDIR="$ECCE_REALUSERHOME/.ECCE" ecce_others_using_services |
25+
awk '{ printf "%s%s %s", sep, $2, $1; sep = ", " }')"
26+
if [ -n "$others" ]; then
27+
echo "ecce-dataserver-stop: another ECCE session or a job of this user is still running ($others) -- data server left running"
28+
exit 3
29+
fi
30+
fi
31+
1232
if [ ! -f "$CONF" ]; then
1333
echo "ecce-dataserver-stop: data server not running (no config at $CONF)"
1434
exit 0

‎packaging/gateway/ecce-gateway-reap‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,15 @@ if [ "$IF_IDLE" = 1 ]; then
166166
[ -z "$(apps_for_state)" ] || exit 0
167167
[ -e "$STATEDIR/mosquitto.server" ] && exit 0
168168
fi
169+
# But only for its own session: another session of this account, on any
170+
# display, or a running job still talks through this broker (#233).
171+
if [ "$EXPLICIT_STOP" = 1 ]; then
172+
others="$(ecce_others_using_services | awk '{ printf "%s%s %s", sep, $2, $1; sep = ", " }')"
173+
if [ -n "$others" ]; then
174+
say "another ECCE session or a job of this user is still running ($others) -- broker left running"
175+
exit 0
176+
fi
177+
fi
169178

170179
brokerpid=""
171180
if [ -f "$STATEDIR/mosquitto.pid" ]; then
@@ -186,7 +195,7 @@ fi
186195

187196
if [ -n "${brokerpid:-}" ]; then
188197
if [ "$EXPLICIT_STOP" = 1 ]; then
189-
say "stop requested, no ECCE session left -- stopping mosquitto broker (pid $brokerpid)"
198+
say "stop requested, no other ECCE session or job left -- stopping mosquitto broker (pid $brokerpid)"
190199
else
191200
say "last ECCE session of this user ended -- stopping its mosquitto broker (pid $brokerpid)"
192201
fi

‎packaging/gateway/ecce-session-lib.sh‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,31 @@ ecce_session_procs() {
164164
} | awk '!seen[$1]++'
165165
}
166166

167+
# The running ECCE programs that still use this state directory's data
168+
# server and broker apart from the given session (default: this
169+
# process's): every program of another session (or of none), and a job
170+
# store or job master of any session, since a job reports through both.
171+
# Lines "<pid> <name> <session id>". SessionLease::othersUsingServices()
172+
# is the C++ copy, which the Quit dialogs use to decide whether to offer
173+
# Quit and Stop Server.
174+
ecce_others_using_services() {
175+
local own="${1-${ECCE_SESSION_ID:-}}" pid name sid home
176+
while read -r pid name sid; do
177+
case "$name" in
178+
eccejobstore | eccejobmaster) ;;
179+
*) [ -n "$own" ] && [ "$sid" = "$own" ] && continue ;;
180+
esac
181+
# A /proc entry may be another state directory's (lease entries are
182+
# this one's, and their programs carry the same environment).
183+
if [ -r "/proc/$pid/environ" ]; then
184+
home="$(tr '\0' '\n' <"/proc/$pid/environ" 2>/dev/null |
185+
sed -n 's/^ECCE_REALUSERHOME=//p' | head -n1)"
186+
[ "${home:-$HOME}" = "${ECCE_REALUSERHOME:-$HOME}" ] || continue
187+
fi
188+
echo "$pid $name $sid"
189+
done < <(ecce_session_procs)
190+
}
191+
167192
# Is an ECCE program of this session running?
168193
ecce_session_alive() {
169194
local pid name sid

‎src/apps/gateway/Gateway.C‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "util/Preferences.H"
3333
#include "util/PreferenceLabels.H"
3434
#include "util/JMSPublisher.H"
35+
#include "util/SessionLease.H"
3536
#include "util/TempStorage.H"
3637

3738
#include "dsm/EDSIServerCentral.H"
@@ -656,7 +657,15 @@ void Gateway::exitGateway()
656657
Iconize(false);
657658
Show(true);
658659
}
659-
ewxMessageDialog dlg(this, "Do you really want to quit?", "Quit ECCE",
660+
// Another session of this account, or a job, still uses the services
661+
// (#233); the stop scripts refuse then too.
662+
bool canStop = !getenv("ECCE_REMOTE_SERVER") && LocalData::dir().empty();
663+
bool inUse = canStop && !SessionLease::othersUsingServices().empty();
664+
string question = "Do you really want to quit?";
665+
if (inUse)
666+
question += "\n\nThe data server and message broker stay running: "
667+
"another ECCE session or a job of yours still uses them.";
668+
ewxMessageDialog dlg(this, question, "Quit ECCE",
660669
wxOK|wxCANCEL|wxICON_QUESTION,
661670
wxDefaultPosition);
662671
// GitHub #52: plain Quit only ever closed the GUI client -- the
@@ -673,7 +682,7 @@ void Gateway::exitGateway()
673682
// misleading, so don't.
674683
// Local data mode has no data server to stop; plain Quit already ends
675684
// the session and the reaper stops the per-user broker.
676-
if (!getenv("ECCE_REMOTE_SERVER") && LocalData::dir().empty())
685+
if (canStop && !inUse)
677686
dlg.AddButton(ID_GATEWAY_QUIT_STOP_SERVER, "Quit and Stop Server");
678687
int result = dlg.ShowModal();
679688
if (result == wxID_OK)
@@ -695,7 +704,7 @@ void Gateway::exitGateway()
695704
// nothing after it runs.
696705
// A local-mode session started no data server; one running belongs to
697706
// a server-mode session elsewhere and is not ours to stop.
698-
if (LocalData::dir().empty()) (void)system("ecce-dataserver-stop");
707+
if (LocalData::dir().empty()) (void)system("ecce-dataserver-stop --if-unused");
699708
(void)system("ecce-gateway-stop");
700709
}
701710
} else {

0 commit comments

Comments
 (0)