@treeseed/sdk 0.10.17 → 0.10.18
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.
- package/dist/operations/services/railway-api.d.ts +1 -6
- package/dist/operations/services/railway-api.js +57 -14
- package/dist/operations/services/railway-deploy.d.ts +17 -0
- package/dist/operations/services/railway-deploy.js +1 -0
- package/dist/reconcile/builtin-adapters.js +9 -13
- package/package.json +1 -1
|
@@ -288,12 +288,7 @@ export declare function ensureRailwayServiceVolume({ projectId, environmentId, s
|
|
|
288
288
|
env?: NodeJS.ProcessEnv | Record<string, string | undefined>;
|
|
289
289
|
fetchImpl?: typeof fetch;
|
|
290
290
|
}): Promise<{
|
|
291
|
-
volume:
|
|
292
|
-
instances: RailwayVolumeInstanceSummary[];
|
|
293
|
-
id: string;
|
|
294
|
-
name: string;
|
|
295
|
-
projectId: string | null;
|
|
296
|
-
} | null;
|
|
291
|
+
volume: RailwayVolumeSummary | null;
|
|
297
292
|
instance: RailwayVolumeInstanceSummary | null;
|
|
298
293
|
created: boolean;
|
|
299
294
|
updated: boolean;
|
|
@@ -840,7 +840,13 @@ async function ensureRailwayServiceInstanceConfiguration({
|
|
|
840
840
|
env = process.env,
|
|
841
841
|
fetchImpl = fetch
|
|
842
842
|
}) {
|
|
843
|
-
|
|
843
|
+
let current = await getRailwayServiceInstance({ serviceId, environmentId, env, fetchImpl });
|
|
844
|
+
if (!current.id) {
|
|
845
|
+
for (let attempt = 0; attempt < 8 && !current.id; attempt += 1) {
|
|
846
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
847
|
+
current = await getRailwayServiceInstance({ serviceId, environmentId, env, fetchImpl });
|
|
848
|
+
}
|
|
849
|
+
}
|
|
844
850
|
if (!current.id) {
|
|
845
851
|
return { instance: current, updated: false };
|
|
846
852
|
}
|
|
@@ -905,12 +911,21 @@ mutation TreeseedRailwayServiceInstanceUpdateLegacy($serviceId: String!, $enviro
|
|
|
905
911
|
}
|
|
906
912
|
throw error;
|
|
907
913
|
}
|
|
908
|
-
|
|
914
|
+
let instance = await getRailwayServiceInstance({
|
|
909
915
|
serviceId,
|
|
910
916
|
environmentId,
|
|
911
917
|
env,
|
|
912
918
|
fetchImpl
|
|
913
919
|
});
|
|
920
|
+
for (let attempt = 0; attempt < 5 && serviceInstanceDrifted(instance, desired); attempt += 1) {
|
|
921
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
922
|
+
instance = await getRailwayServiceInstance({
|
|
923
|
+
serviceId,
|
|
924
|
+
environmentId,
|
|
925
|
+
env,
|
|
926
|
+
fetchImpl
|
|
927
|
+
});
|
|
928
|
+
}
|
|
914
929
|
return {
|
|
915
930
|
instance: {
|
|
916
931
|
id: instance.id || current.id,
|
|
@@ -929,6 +944,9 @@ mutation TreeseedRailwayServiceInstanceUpdateLegacy($serviceId: String!, $enviro
|
|
|
929
944
|
updated: true
|
|
930
945
|
};
|
|
931
946
|
}
|
|
947
|
+
function serviceInstanceDrifted(current, desired) {
|
|
948
|
+
return desired.buildCommand !== null && desired.buildCommand !== current.buildCommand || desired.startCommand !== null && desired.startCommand !== current.startCommand || desired.cronSchedule !== null && desired.cronSchedule !== current.cronSchedule || desired.rootDirectory !== null && desired.rootDirectory !== current.rootDirectory || desired.healthcheckPath !== null && desired.healthcheckPath !== current.healthcheckPath || desired.healthcheckTimeoutSeconds !== null && desired.healthcheckTimeoutSeconds !== current.healthcheckTimeoutSeconds || desired.runtimeMode !== null && desired.runtimeMode !== current.runtimeMode;
|
|
949
|
+
}
|
|
932
950
|
async function listRailwayVariables({
|
|
933
951
|
projectId,
|
|
934
952
|
environmentId,
|
|
@@ -1193,23 +1211,37 @@ async function ensureRailwayServiceVolume({
|
|
|
1193
1211
|
...candidate,
|
|
1194
1212
|
instances: candidate.instances.filter(isActiveRailwayVolumeInstance)
|
|
1195
1213
|
})).filter((candidate) => candidate.instances.length > 0);
|
|
1196
|
-
let volume = activeVolumes.find(
|
|
1197
|
-
(candidate) => candidate.instances.some((instance2) => instance2.serviceId === serviceId && instance2.environmentId === environmentId)
|
|
1198
|
-
) ?? activeVolumes.find(
|
|
1214
|
+
let volume = findRailwayVolumeForService(volumes, serviceId, environmentId) ?? activeVolumes.find(
|
|
1199
1215
|
(candidate) => candidate.name === name && candidate.instances.some((instance2) => instance2.environmentId === environmentId)
|
|
1200
1216
|
) ?? null;
|
|
1201
1217
|
let created = false;
|
|
1202
1218
|
let updated = false;
|
|
1203
1219
|
const createReplacementVolume = async () => {
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1220
|
+
let replacement;
|
|
1221
|
+
try {
|
|
1222
|
+
replacement = await createRailwayVolume({
|
|
1223
|
+
projectId,
|
|
1224
|
+
environmentId,
|
|
1225
|
+
serviceId,
|
|
1226
|
+
name,
|
|
1227
|
+
mountPath,
|
|
1228
|
+
env,
|
|
1229
|
+
fetchImpl
|
|
1230
|
+
});
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
if (!looksLikeRailwayVolumeCreateRace(error)) {
|
|
1233
|
+
throw error;
|
|
1234
|
+
}
|
|
1235
|
+
for (let attempt = 0; attempt < 8; attempt += 1) {
|
|
1236
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
1237
|
+
const refreshed = await listRailwayVolumes({ projectId, env, fetchImpl });
|
|
1238
|
+
const existing = findRailwayVolumeForService(refreshed, serviceId, environmentId);
|
|
1239
|
+
if (existing) {
|
|
1240
|
+
return existing;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
throw error;
|
|
1244
|
+
}
|
|
1213
1245
|
created = true;
|
|
1214
1246
|
return replacement;
|
|
1215
1247
|
};
|
|
@@ -1259,6 +1291,17 @@ async function ensureRailwayServiceVolume({
|
|
|
1259
1291
|
}
|
|
1260
1292
|
return { volume, instance, created, updated };
|
|
1261
1293
|
}
|
|
1294
|
+
function findRailwayVolumeForService(volumes, serviceId, environmentId) {
|
|
1295
|
+
return volumes.find(
|
|
1296
|
+
(candidate) => candidate.instances.some(
|
|
1297
|
+
(instance) => instance.serviceId === serviceId && instance.environmentId === environmentId && isActiveRailwayVolumeInstance(instance)
|
|
1298
|
+
)
|
|
1299
|
+
) ?? null;
|
|
1300
|
+
}
|
|
1301
|
+
function looksLikeRailwayVolumeCreateRace(error) {
|
|
1302
|
+
const message = error instanceof Error ? error.message : String(error ?? "");
|
|
1303
|
+
return /would have \d+ volumes attached|can only have one volume|not authorized/iu.test(message);
|
|
1304
|
+
}
|
|
1262
1305
|
async function listRailwayCustomDomains({
|
|
1263
1306
|
projectId,
|
|
1264
1307
|
environmentId,
|
|
@@ -144,6 +144,23 @@ export declare function planRailwayServiceLink(service: any, { env }?: {
|
|
|
144
144
|
args: string[];
|
|
145
145
|
cwd: any;
|
|
146
146
|
};
|
|
147
|
+
export declare function ensureRailwayServiceVolumeWithCliFallback({ tenantRoot, projectId, environmentId, environmentName, serviceId, serviceName, name, mountPath, preferCli, env, }: {
|
|
148
|
+
tenantRoot: any;
|
|
149
|
+
projectId: any;
|
|
150
|
+
environmentId: any;
|
|
151
|
+
environmentName: any;
|
|
152
|
+
serviceId: any;
|
|
153
|
+
serviceName: any;
|
|
154
|
+
name: any;
|
|
155
|
+
mountPath: any;
|
|
156
|
+
preferCli?: boolean | undefined;
|
|
157
|
+
env?: NodeJS.ProcessEnv | undefined;
|
|
158
|
+
}): Promise<{
|
|
159
|
+
volume: any;
|
|
160
|
+
instance: any;
|
|
161
|
+
created: boolean;
|
|
162
|
+
updated: boolean;
|
|
163
|
+
}>;
|
|
147
164
|
export declare function deployRailwayService(tenantRoot: any, service: any, { dryRun, write, prefix, env, }?: {
|
|
148
165
|
dryRun?: boolean;
|
|
149
166
|
write?: TreeseedBootstrapWriter;
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
configuredRailwayServices,
|
|
33
33
|
deriveRailwayMarketOperationsRunnerVolumeName,
|
|
34
34
|
ensureRailwayProjectContext,
|
|
35
|
+
ensureRailwayServiceVolumeWithCliFallback,
|
|
35
36
|
runRailway,
|
|
36
37
|
validateRailwayDeployPrerequisites
|
|
37
38
|
} from "../operations/services/railway-deploy.js";
|
|
@@ -42,7 +43,6 @@ import {
|
|
|
42
43
|
ensureRailwayProject,
|
|
43
44
|
ensureRailwayService,
|
|
44
45
|
ensureRailwayServiceInstanceConfiguration,
|
|
45
|
-
ensureRailwayServiceVolume,
|
|
46
46
|
getRailwayServiceInstance,
|
|
47
47
|
getRailwayProject,
|
|
48
48
|
listRailwayCustomDomains,
|
|
@@ -1568,12 +1568,16 @@ async function syncRailwayEnvironmentForScope(input, { dryRun = false } = {}) {
|
|
|
1568
1568
|
});
|
|
1569
1569
|
if (entry.configuredService.volumeMountPath) {
|
|
1570
1570
|
const volumeName = entry.configuredService.key === "marketOperationsRunner" ? deriveRailwayMarketOperationsRunnerVolumeName(entry.service.name, entry.environment.name) : `${entry.service.name}-volume`;
|
|
1571
|
-
const volume = await
|
|
1571
|
+
const volume = await ensureRailwayServiceVolumeWithCliFallback({
|
|
1572
|
+
tenantRoot: input.context.tenantRoot,
|
|
1572
1573
|
projectId: entry.project.id,
|
|
1573
1574
|
environmentId: entry.environment.id,
|
|
1575
|
+
environmentName: entry.environment.name,
|
|
1574
1576
|
serviceId: entry.service.id,
|
|
1577
|
+
serviceName: entry.service.name,
|
|
1575
1578
|
name: volumeName,
|
|
1576
1579
|
mountPath: entry.configuredService.volumeMountPath,
|
|
1580
|
+
preferCli: entry.configuredService.key === "marketOperationsRunner",
|
|
1577
1581
|
env: topology.env
|
|
1578
1582
|
});
|
|
1579
1583
|
if (!volume.instance?.serviceId) {
|
|
@@ -1660,7 +1664,7 @@ async function ensureRailwayMarketDatabaseForScope(input, topology) {
|
|
|
1660
1664
|
env: topology.env
|
|
1661
1665
|
});
|
|
1662
1666
|
}
|
|
1663
|
-
for (let attempt = 0; attempt <
|
|
1667
|
+
for (let attempt = 0; attempt < 20; attempt += 1) {
|
|
1664
1668
|
const existingVolumes = await listRailwayVolumes({
|
|
1665
1669
|
projectId: firstService.project.id,
|
|
1666
1670
|
env: topology.env
|
|
@@ -1669,18 +1673,10 @@ async function ensureRailwayMarketDatabaseForScope(input, topology) {
|
|
|
1669
1673
|
(instance) => instance.serviceId === postgresService.id && instance.environmentId === firstService.environment?.id && instance.mountPath === "/var/lib/postgresql/data"
|
|
1670
1674
|
));
|
|
1671
1675
|
if (attached) {
|
|
1672
|
-
|
|
1676
|
+
return;
|
|
1673
1677
|
}
|
|
1674
|
-
await new Promise((resolve2) => setTimeout(resolve2,
|
|
1678
|
+
await new Promise((resolve2) => setTimeout(resolve2, 3e3));
|
|
1675
1679
|
}
|
|
1676
|
-
await ensureRailwayServiceVolume({
|
|
1677
|
-
projectId: firstService.project.id,
|
|
1678
|
-
environmentId: firstService.environment.id,
|
|
1679
|
-
serviceId: postgresService.id,
|
|
1680
|
-
name: `postgres-${topology.scope === "prod" ? "prod" : topology.scope}-data`,
|
|
1681
|
-
mountPath: "/var/lib/postgresql/data",
|
|
1682
|
-
env: topology.env
|
|
1683
|
-
});
|
|
1684
1680
|
}
|
|
1685
1681
|
async function observeRailwayUnit(input, { refresh = false } = {}) {
|
|
1686
1682
|
let attempt = 0;
|