Skip to content

Commit 5e46bec

Browse files
committed
fix(native-pipeline): cap runtime session pile-up under the 6-user trial license
The portable-app runtime runs under a developer/trial license limited to 6 concurrent named users. Every Maestro flow does `launchApp clearState:true`, which clears device state but opens a FRESH server session that lingers for the default 10-min SessionTimeout. Widgets whose flow count (+smoke launch +retries) exceeds 6 therefore wedge mid-suite on the "Maximum number of sessions exceeded" screen — Precondition can't find the Widgets menu and the shard fails. This hit background-image (8 flows), safe-area-view (7), accordion (6), and the js-tests job (mobile-resources 5 + nanoflow 3 = 8); every <=5-flow widget stays green. Fast-fail un-masked this rather than causing it: the old 4x-retry/long-timeout config spread a shard's launches past the 10-min window, so early sessions expired and freed slots before later retries ran (eventual green, just slow). start-mendix-runtime now shortens the server session idle timeout (RUNTIME_PARAMS_SESSIONTIMEOUT=60000, via a tunable session-timeout-ms input) and reaps expired sessions promptly (RUNTIME_PARAMS_CLUSTERMANAGERACTIONINTERVAL =30000), both ridden through the portable app's existing HOCON env overrides. At ~30s/flow this holds peak concurrency to ~2-3, well under 6, with no test changes. Confirmed against run 28168923730's safe-area-view runtime log. Also reword script/action/workflow comments and the scripts README to describe the current design instead of narrating what it replaced.
1 parent c12341e commit 5e46bec

5 files changed

Lines changed: 35 additions & 23 deletions

File tree

.github/actions/setup-tools/action.yaml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ outputs:
77
runs:
88
using: "composite"
99
steps:
10-
# NOTE: Python and Node/pnpm setup were both removed here.
11-
# - Python was only needed by the old m2ee runtime (replaced by the portable app package).
12-
# - Node/pnpm `install` ran the root `prepare` lifecycle (building tool packages), which the
13-
# maestro test jobs don't need and which flaked with ENOTEMPTY. Maestro is a standalone
14-
# binary, so the test jobs need only Java + Maestro.
10+
# Test jobs need only Java + Maestro:
11+
# - the portable app package bundles the runtime, so there's no CDN runtime download and no
12+
# m2ee tooling to set up (and nothing here needs Python).
13+
# - Maestro is a standalone binary, so there's no Node/pnpm install — which would also run the
14+
# root `prepare` lifecycle the test jobs don't need (a known ENOTEMPTY flake source).
1515

1616
- name: "Setup Java 21"
1717
id: setup-java
@@ -20,10 +20,6 @@ runs:
2020
distribution: "temurin"
2121
java-version: "21"
2222

23-
# NOTE: the Mendix-runtime tarball and m2ee-tools caches were removed here.
24-
# The portable app package bundles the runtime, so the test jobs no longer
25-
# download the runtime from the CDN or clone m2ee-tools.
26-
2723
- name: "Install Maestro"
2824
uses: ./.github/actions/setup-maestro
2925

.github/actions/start-mendix-runtime/action.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,17 @@ inputs:
2121
description: "How long to wait for the runtime to become ready before failing"
2222
required: false
2323
default: "300"
24+
session-timeout-ms:
25+
description: >
26+
Server-side session idle timeout (ms). The runtime uses a trial license capped at
27+
6 concurrent named users, and every Maestro flow does `launchApp clearState: true`,
28+
which starts a FRESH server session while the previous one lingers for the full
29+
timeout. With Mendix's 10-min default, a widget with >5 flows piles past 6 sessions
30+
and the next login fails with "Maximum number of sessions exceeded". A short idle
31+
timeout lets each flow's session expire before the next ones accumulate. Active
32+
sessions aren't affected — client requests keep resetting the idle timer mid-flow.
33+
required: false
34+
default: "60000"
2435
runs:
2536
using: "composite"
2637
steps:
@@ -32,6 +43,13 @@ runs:
3243
M2EE_ADMIN_PASS: ${{ inputs.admin-pass }}
3344
RUNTIME_URL: ${{ inputs.runtime-url }}
3445
TIMEOUT_SECONDS: ${{ inputs.timeout-seconds }}
46+
# Read by the portable app's HOCON config (etc/variables.conf: ${?RUNTIME_PARAMS_*}),
47+
# inherited by the JVM started below. Caps session pile-up under the 6-user trial
48+
# license — see the session-timeout-ms input for the full rationale.
49+
RUNTIME_PARAMS_SESSIONTIMEOUT: ${{ inputs.session-timeout-ms }}
50+
# Reap expired sessions promptly (default cluster cleanup runs only every 5 min, which
51+
# would hold license slots long after the sessions go idle).
52+
RUNTIME_PARAMS_CLUSTERMANAGERACTIONINTERVAL: "30000"
3553
run: |
3654
set -euo pipefail
3755

.github/scripts/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@ would fail.
6464

6565
- **determine-nt-version.mjs** — resolves the Native Template release/branch from the
6666
Mendix version. Node ESM, no external deps (uses global `fetch` + a small version
67-
comparator); run with the runner's preinstalled `node`. Replaced the former
68-
`determine-nt-version.py` (the Python toolchain — `setup-python` / `pip install`
69-
was dropped). Fails loudly rather than silently pinning `master`.
67+
comparator); run with the runner's preinstalled `node`. Fails loudly rather than
68+
silently pinning `master`.
7069
- **mxbuild.Dockerfile** — Docker image for mxbuild.
7170

7271
> The Mendix runtime for the test jobs is produced as a **portable app package**
7372
> (`mxbuild --target=portable-app-package`) in the `project` job and started by the
7473
> `start-mendix-runtime` composite action, which waits for a real readiness probe.
75-
> This replaced the old `setup-runtime.sh` / `start-runtime-with-verification.sh`
76-
> scripts and the `m2ee-native.yml` config (which cloned m2ee-tools and downloaded
77-
> the runtime from the CDN).
74+
> That runtime runs under a 6-user trial license, so the action shortens the server
75+
> session idle timeout (`RUNTIME_PARAMS_SESSIONTIMEOUT`) — each Maestro flow opens a
76+
> fresh session via `launchApp clearState`, and a short timeout lets them expire
77+
> between flows instead of piling up past the cap.

.github/scripts/determine-nt-version.mjs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#!/usr/bin/env node
22
// Resolve which Native Template release/branch to build against, given the resolved Mendix
3-
// version. Ported from determine-nt-version.py (Phase 5, D3: standardise pipeline scripting on
4-
// Node/JS and drop the Python toolchain — no more setup-python / `pip install`). No external
5-
// deps: uses the global fetch + a small dotted-version comparator instead of requests/packaging.
3+
// version. No external deps: uses the global fetch + a small dotted-version comparator, so it
4+
// runs on the runner's preinstalled node with no setup step.
65

76
import fs from "node:fs";
87

.github/workflows/NativePipeline.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,7 @@ jobs:
248248
- name: "Build resources"
249249
# On a full build with an exact cache hit every widget's dist is already current, so
250250
# skip the slow rollup/babel rebuild. Otherwise build the scoped widgets + JS actions
251-
# in one pnpm invocation (multiple --filter targets run concurrently) instead of the
252-
# old one-at-a-time loop.
251+
# in one pnpm invocation (multiple --filter targets run concurrently).
253252
run: |
254253
if [ "${{ needs.scope.outputs.full_build }}" = "true" ] && [ "${{ steps.resources-cache.outputs.cache-hit }}" = "true" ]; then
255254
echo "Full build with cached resources — skipping rebuild."
@@ -359,9 +358,9 @@ jobs:
359358
fi
360359
- name: "Register widgets in the test project"
361360
# Run unconditionally: update-widgets must sync the project's widget definitions with the
362-
# mpks in widgets/ regardless of whether THIS run overlaid fresh ones. Previously it was
363-
# nested in the mpk-move guard, so a `js-actions` dispatch (or any run that builds no
364-
# mpks) skipped it and left stale Atlas widget defs for the portable-app build.
361+
# mpks in widgets/ regardless of whether THIS run overlaid fresh ones. Must NOT be nested
362+
# in the mpk-move guard a `js-actions` dispatch (or any run that builds no mpks) would
363+
# then skip it and leave stale Atlas widget defs for the portable-app build.
365364
shell: bash
366365
run: mx update-widgets --loose-version-check Native-Mobile-Resources-main/NativeComponentsTestProject.mpr
367366
- name: "Move mobile-resources"

0 commit comments

Comments
 (0)