@forge/cli
14.1.0-next.1-experimental-13c2f8d14.1.0-next.21-experimental-554d417
out/service/local-storage-lifecycle.js−
out/service/local-storage-lifecycle.jsDeleted−167
Index: package/out/service/local-storage-lifecycle.js
===================================================================
--- package/out/service/local-storage-lifecycle.js
+++ package/out/service/local-storage-lifecycle.js
@@ -1,167 +0,0 @@
-"use strict";
-Object.defineProperty(exports, "__esModule", { value: true });
-exports.LocalStorageLifecycle = exports.localStorageComposeConfig = exports.LocalStorageStartupError = exports.SQL_IMAGE = exports.KVS_IMAGE = exports.TIDB_IMAGE = exports.LOCAL_STORAGE_VOLUME = exports.LOCAL_STORAGE_PROJECT = void 0;
-const tslib_1 = require("tslib");
-const fs_1 = tslib_1.__importDefault(require("fs"));
-const path_1 = tslib_1.__importDefault(require("path"));
-const cli_shared_1 = require("@forge/cli-shared");
-const yaml_1 = tslib_1.__importDefault(require("yaml"));
-exports.LOCAL_STORAGE_PROJECT = 'forge-local-storage-v1';
-exports.LOCAL_STORAGE_VOLUME = 'forge-local-storage-tidb-data-v1';
-exports.TIDB_IMAGE = 'pingcap/tidb:v8.5.3';
-exports.KVS_IMAGE = 'docker-public.packages.atlassian.com/atlassian/forge-kvs-emulator:latest';
-exports.SQL_IMAGE = 'docker-public.packages.atlassian.com/atlassian/forge-sql-emulator:latest';
-const SERVICE_DETAILS = {
- kvs: { service: 'kvs', endpoint: 'http://127.0.0.1:18090', healthPath: '/deep-check' },
- sql: { service: 'sql', endpoint: 'http://127.0.0.1:18091', healthPath: '/deepcheck' }
-};
-class LocalStorageStartupError extends cli_shared_1.UserError {
-}
-exports.LocalStorageStartupError = LocalStorageStartupError;
-const localStorageComposeConfig = (images = { tidb: exports.TIDB_IMAGE, kvs: exports.KVS_IMAGE, sql: exports.SQL_IMAGE }) => ({
- services: {
- tidb: {
- image: images.tidb,
- command: ['--store=unistore', '--path=/var/lib/tidb'],
- restart: 'unless-stopped',
- volumes: [`${exports.LOCAL_STORAGE_VOLUME}:/var/lib/tidb`]
- },
- kvs: {
- image: images.kvs,
- restart: 'unless-stopped',
- depends_on: ['tidb'],
- environment: {
- FORGE_KVS_EMULATOR_ADDRESS: '0.0.0.0:18090',
- FORGE_TIDB_DSN: 'root@tcp(tidb:4000)/',
- FORGE_KVS_DATABASE: 'forge_local_kvs'
- },
- ports: ['127.0.0.1:18090:18090']
- },
- sql: {
- image: images.sql,
- restart: 'unless-stopped',
- depends_on: ['tidb'],
- environment: {
- FORGE_SQL_EMULATOR_ADDRESS: '0.0.0.0:18091',
- FORGE_SQL_EMULATOR_ALLOW_NON_LOOPBACK: '1',
- FORGE_TIDB_DSN: 'root@tcp(tidb:4000)/'
- },
- ports: ['127.0.0.1:18091:18091']
- }
- },
- volumes: {
- [exports.LOCAL_STORAGE_VOLUME]: { name: exports.LOCAL_STORAGE_VOLUME }
- }
-});
-exports.localStorageComposeConfig = localStorageComposeConfig;
-class LocalStorageLifecycle {
- composePath;
- compose;
- docker;
- readinessTimeoutMs;
- pollIntervalMs;
- pullImages;
- fetchClient;
- pause;
- constructor(composePath, compose, docker, options = {}) {
- this.composePath = composePath;
- this.compose = compose;
- this.docker = docker;
- this.readinessTimeoutMs = options.readinessTimeoutMs ?? 60_000;
- this.pollIntervalMs = options.pollIntervalMs ?? 500;
- this.pullImages = options.pullImages ?? true;
- this.fetchClient = options.fetch ?? fetch;
- this.pause = options.pause ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
- }
- static create(composePath, docker, logger) {
- return new LocalStorageLifecycle(composePath, new cli_shared_1.ComposeProjectLifecycle(composePath, exports.LOCAL_STORAGE_PROJECT, logger), docker);
- }
- writeComposeFile() {
- fs_1.default.mkdirSync(path_1.default.dirname(this.composePath), { recursive: true });
- fs_1.default.writeFileSync(this.composePath, yaml_1.default.stringify((0, exports.localStorageComposeConfig)()), { mode: 0o600 });
- }
- async start(offerings) {
- await this.docker.getDockerVersion(false);
- this.writeComposeFile();
- const services = ['tidb', ...offerings.map((offering) => SERVICE_DETAILS[offering].service)];
- try {
- const currentStates = await this.compose.states();
- const alreadyReady = await Promise.all(offerings.map(async (offering) => {
- const service = SERVICE_DETAILS[offering].service;
- return (currentStates.some((item) => item.service === service && item.state.toLowerCase() === 'running') &&
- (await this.isReady(offering)));
- }));
- if (alreadyReady.every(Boolean))
- return;
- if (this.pullImages)
- await this.compose.pull(services);
- await this.compose.up(services);
- for (const offering of offerings)
- await this.waitUntilReady(offering);
- }
- catch (error) {
- const diagnostics = await this.diagnostics(offerings);
- try {
- await this.compose.down();
- }
- catch { }
- const suffix = diagnostics ? `\n\nRecent container logs:\n${diagnostics}` : '';
- throw new LocalStorageStartupError(`${error.message}${suffix}`);
- }
- }
- async status() {
- await this.docker.getDockerVersion(false);
- this.writeComposeFile();
- const states = await this.compose.states();
- const entries = await Promise.all(['kvs', 'sql'].map(async (offering) => {
- const details = SERVICE_DETAILS[offering];
- const container = states.find((item) => item.service === details.service);
- const running = container?.state.toLowerCase() === 'running';
- const healthy = Boolean(running && (await this.isReady(offering)));
- return [
- offering,
- {
- state: healthy ? 'running' : running ? 'unhealthy' : 'stopped',
- healthy,
- endpoint: healthy ? details.endpoint : undefined,
- container
- }
- ];
- }));
- return Object.fromEntries(entries);
- }
- async stop() {
- await this.docker.getDockerVersion(false);
- this.writeComposeFile();
- await this.compose.down();
- }
- async isReady(offering) {
- const details = SERVICE_DETAILS[offering];
- try {
- const response = await this.fetchClient(`${details.endpoint}${details.healthPath}`);
- return response.ok;
- }
- catch {
- return false;
- }
- }
- async waitUntilReady(offering) {
- const deadline = Date.now() + this.readinessTimeoutMs;
- do {
- if (await this.isReady(offering))
- return;
- await this.pause(this.pollIntervalMs);
- } while (Date.now() < deadline);
- throw new Error(`${offering.toUpperCase()} did not become ready within ${this.readinessTimeoutMs / 1000}s`);
- }
- async diagnostics(offerings) {
- const services = ['tidb', ...offerings.map((offering) => SERVICE_DETAILS[offering].service)];
- const logs = await Promise.all(services.map(async (service) => {
- const output = await this.compose.logs(service);
- return output ? `[${service}]\n${output}` : '';
- }));
- return logs.filter(Boolean).join('\n\n');
- }
-}
-exports.LocalStorageLifecycle = LocalStorageLifecycle;
-//# sourceMappingURL=local-storage-lifecycle.js.map
\ No newline at end of file