@stacksjs/ts-cloud 0.7.33 → 0.7.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1011,6 +1011,8 @@ function buildRpxProvisionScript(options) {
1011
1011
  const poolEnv = [`Environment=RPX_UPSTREAM_TIMEOUT=${upstreamTimeout}`];
1012
1012
  if (typeof proxy.maxUpstreamConns === "number")
1013
1013
  poolEnv.push(`Environment=RPX_MAX_UPSTREAM_CONNS=${proxy.maxUpstreamConns}`);
1014
+ const memoryHigh = proxy.memoryHigh ?? "512M";
1015
+ const memoryMax = proxy.memoryMax ?? "768M";
1014
1016
  return [
1015
1017
  "set -euo pipefail",
1016
1018
  `mkdir -p ${RPX_DIR} ${RPX_SITES_DIR} ${certsDir} ${RPX_INSTALL_DIR}`,
@@ -1035,6 +1037,10 @@ function buildRpxProvisionScript(options) {
1035
1037
  `WorkingDirectory=${RPX_INSTALL_DIR}`,
1036
1038
  `Environment=BUN_INSTALL=/root/.bun`,
1037
1039
  ...poolEnv,
1040
+ "MemoryAccounting=true",
1041
+ `MemoryHigh=${memoryHigh}`,
1042
+ `MemoryMax=${memoryMax}`,
1043
+ "OOMPolicy=stop",
1038
1044
  "Restart=always",
1039
1045
  "RestartSec=5",
1040
1046
  "LimitNOFILE=1048576",
@@ -1476,7 +1482,8 @@ function buildUbuntuBootstrapScript(options = {}) {
1476
1482
  servicesProvision,
1477
1483
  caddyfile,
1478
1484
  rpxProvision,
1479
- baked = false
1485
+ baked = false,
1486
+ swapGb = 2
1480
1487
  } = options;
1481
1488
  const packages = new Set(systemPackages);
1482
1489
  if (database === "sqlite")
@@ -1488,6 +1495,25 @@ function buildUbuntuBootstrapScript(options = {}) {
1488
1495
  let script = `#!/bin/bash
1489
1496
  set -euo pipefail
1490
1497
  `;
1498
+ const swapSizeGb = Math.floor(swapGb);
1499
+ if (swapSizeGb > 0) {
1500
+ script += `
1501
+ # Swap: a swapless box under memory pressure lets the kernel OOM killer choose
1502
+ # victims box-wide (the gateway, a tenant app, postgres). A modest swapfile
1503
+ # with low swappiness gives the kernel headroom without hurting responsiveness.
1504
+ if ! swapon --show=NAME --noheadings 2>/dev/null | grep -qx '/swapfile'; then
1505
+ if [ ! -f /swapfile ]; then
1506
+ fallocate -l ${swapSizeGb}G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=${swapSizeGb * 1024} status=none
1507
+ chmod 600 /swapfile
1508
+ mkswap /swapfile >/dev/null
1509
+ fi
1510
+ swapon /swapfile
1511
+ fi
1512
+ grep -qE '^/swapfile\\s' /etc/fstab || echo '/swapfile none swap sw 0 0' >> /etc/fstab
1513
+ echo 'vm.swappiness=10' > /etc/sysctl.d/99-ts-cloud-swap.conf
1514
+ sysctl -w vm.swappiness=10 >/dev/null
1515
+ `;
1516
+ }
1491
1517
  if (!baked) {
1492
1518
  script += `
1493
1519
  export DEBIAN_FRONTEND=noninteractive
@@ -2466,7 +2492,8 @@ class HetznerDriver {
2466
2492
  phpProvision: provision.phpProvision,
2467
2493
  servicesProvision: provision.servicesProvision,
2468
2494
  rpxProvision,
2469
- baked
2495
+ baked,
2496
+ swapGb: compute.swapGb
2470
2497
  });
2471
2498
  const userData = wrapCloudInitUserData(bootstrap);
2472
2499
  const serverType = resolveHetznerServerType(compute.size);
@@ -2537,7 +2564,7 @@ class HetznerDriver {
2537
2564
  { direction: "in", protocol: "tcp", port: "7700", source_ips: [network.ip_range] }
2538
2565
  ]);
2539
2566
  const servicesProvision = buildFleetServicesBoxProvision(config);
2540
- const servicesUserData = wrapCloudInitUserData(buildUbuntuBootstrapScript({ runtime: "php", servicesProvision, baked }));
2567
+ const servicesUserData = wrapCloudInitUserData(buildUbuntuBootstrapScript({ runtime: "php", servicesProvision, baked, swapGb: compute.swapGb }));
2541
2568
  const all = await this.client.listServers().catch(() => []);
2542
2569
  const newServerIds = [];
2543
2570
  let svcServer = all.find((s) => matchesTsCloudLabels(s.labels, slug, environment, "services"));
@@ -2573,7 +2600,7 @@ class HetznerDriver {
2573
2600
  optimizeForProduction: compute.php?.optimizeForProduction,
2574
2601
  ini: compute.php?.ini
2575
2602
  });
2576
- const appUserData = wrapCloudInitUserData(buildUbuntuBootstrapScript({ runtime: "php", phpProvision: appPhp, servicesProvision: appProvision, baked }));
2603
+ const appUserData = wrapCloudInitUserData(buildUbuntuBootstrapScript({ runtime: "php", phpProvision: appPhp, servicesProvision: appProvision, baked, swapGb: compute.swapGb }));
2577
2604
  const existingApp = all.filter((s) => matchesTsCloudLabels(s.labels, slug, environment, "app"));
2578
2605
  const appServerIds = existingApp.map((s) => s.id);
2579
2606
  if (existingApp.length > topology.appServers) {
@@ -2707,7 +2734,7 @@ class HetznerDriver {
2707
2734
  { direction: "in", protocol: "tcp", port: "7700", source_ips: [network.ip_range] }
2708
2735
  ]);
2709
2736
  const servicesProvision = buildFleetServicesBoxProvision(config);
2710
- const servicesUserData = wrapCloudInitUserData(buildUbuntuBootstrapScript({ runtime: "bun", servicesProvision, baked }));
2737
+ const servicesUserData = wrapCloudInitUserData(buildUbuntuBootstrapScript({ runtime: "bun", servicesProvision, baked, swapGb: compute.swapGb }));
2711
2738
  let svcServer = all.find((s) => matchesTsCloudLabels(s.labels, slug, environment, "services"));
2712
2739
  if (!svcServer) {
2713
2740
  const { server, action } = await this.client.createServer({
@@ -2739,7 +2766,8 @@ class HetznerDriver {
2739
2766
  systemPackages: compute.systemPackages,
2740
2767
  database: config.infrastructure?.database,
2741
2768
  servicesProvision: appProvisionScripts.servicesProvision,
2742
- baked
2769
+ baked,
2770
+ swapGb: compute.swapGb
2743
2771
  }));
2744
2772
  const existingApp = all.filter((s) => matchesTsCloudLabels(s.labels, slug, environment, "app"));
2745
2773
  const appServerIds = existingApp.map((s) => s.id);
@@ -29,7 +29,7 @@ import {
29
29
  resolveSiteKind,
30
30
  resolveUiSource,
31
31
  siteInstallBase
32
- } from "./chunk-m0zayf6n.js";
32
+ } from "./chunk-e6xhm3qe.js";
33
33
  import {
34
34
  artifactKey,
35
35
  composeServerlessAppTemplate,
@@ -12,7 +12,7 @@ import {
12
12
  sanitizeCloudConfig,
13
13
  setMaintenance,
14
14
  startLocalDashboardServer
15
- } from "../chunk-1nfkggdw.js";
15
+ } from "../chunk-jvp3s3na.js";
16
16
  import {
17
17
  buildAndPushServerlessImage
18
18
  } from "../chunk-tskj9fay.js";
@@ -30,7 +30,7 @@ import {
30
30
  resolveUiSource,
31
31
  siteInstallBase,
32
32
  validateDeploymentConfig
33
- } from "../chunk-m0zayf6n.js";
33
+ } from "../chunk-e6xhm3qe.js";
34
34
  import"../chunk-stt1z5cx.js";
35
35
  import"../chunk-93hjhs78.js";
36
36
  import {
@@ -50,7 +50,7 @@ import {
50
50
  waitForCloudInit,
51
51
  waitForSsh,
52
52
  wrapCloudInitUserData
53
- } from "../chunk-m0zayf6n.js";
53
+ } from "../chunk-e6xhm3qe.js";
54
54
  import"../chunk-stt1z5cx.js";
55
55
  import"../chunk-93hjhs78.js";
56
56
  import"../chunk-qpj3edwz.js";
@@ -47,6 +47,16 @@ export interface UbuntuBootstrapOptions {
47
47
  * boot near-instant. @default false
48
48
  */
49
49
  baked?: boolean;
50
+ /**
51
+ * Swapfile size in GB, from `compute.swapGb`. Small shared boxes run several
52
+ * tenants + services with no swap at all, so a memory spike (deploy, bun
53
+ * install, on-box builds) leaves the kernel OOM killer picking victims
54
+ * box-wide. Provisioned at the very top of the bootstrap — BEFORE the
55
+ * memory-hungry installs — on cold and baked boots alike (a golden image
56
+ * deliberately bakes no swap; see the image recipe). Idempotent: skipped
57
+ * when `/swapfile` is already active. `0` disables. @default 2
58
+ */
59
+ swapGb?: number;
50
60
  }
51
61
  /**
52
62
  * Build the Ubuntu provisioning bash script (with `#!/bin/bash` shebang).
package/dist/index.js CHANGED
@@ -55,7 +55,7 @@ import {
55
55
  sanitizeCloudConfig,
56
56
  setMaintenance,
57
57
  startLocalDashboardServer
58
- } from "./chunk-1nfkggdw.js";
58
+ } from "./chunk-jvp3s3na.js";
59
59
  import {
60
60
  buildAndPushServerlessImage
61
61
  } from "./chunk-tskj9fay.js";
@@ -105,7 +105,7 @@ import {
105
105
  waitForCloudInit,
106
106
  waitForSsh,
107
107
  wrapCloudInitUserData
108
- } from "./chunk-m0zayf6n.js";
108
+ } from "./chunk-e6xhm3qe.js";
109
109
  import {
110
110
  ABTestManager,
111
111
  AI,