3f1d816ac0
Story 10.4 — pipeline установки subgraph-расширения:
1. (опц.) OCI token у CA-auth → docker pull образа;
2. (опц.) docker compose up сервиса;
3. healthcheck poll по url subgraph'а до 200 OK;
4. upsert в subgraph_registry (Apollo Gateway за ≤10с подхватит);
5. на failure — composeDown rollback + discriminated outcome {applied|failed}.
InstallController стал тонкой обёрткой над InstallOrchestratorService.
Внешние зависимости (docker shell / fetch / CA-auth) изолированы за
портами; тесты (7/7 green) гоняют сценарий через ин-мемори моки без
реального docker daemon'а и сети.
Что ОСТАЁТСЯ для отдельной ветки под этим зонтиком:
- wiring approve→install REST из mono controller (mutation approvePackage);
- desktop notification после успешного install'а;
- E2E на реальном compose + chatcoop subgraph (Story 10.8).
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import 'reflect-metadata';
|
||
import { NestFactory } from '@nestjs/core';
|
||
import { DataSource } from 'typeorm';
|
||
import { AppModule } from './app.module';
|
||
import { loadAppConfig } from './config/app-config';
|
||
import { SubgraphRegistryEntity } from './gateway/subgraph-registry.entity';
|
||
|
||
/**
|
||
* Перед стартом Apollo Gateway seed'им запись core-subgraph'а в registry,
|
||
* иначе IntrospectAndCompose упадёт с "пустой registry".
|
||
*
|
||
* Bootstrap делается в отдельной DataSource (минуя Nest DI), чтобы быть
|
||
* уверенным что seed произошёл ДО запуска GraphQLModule.forRootAsync.
|
||
*/
|
||
async function seedCoreSubgraph(cfg: ReturnType<typeof loadAppConfig>) {
|
||
const ds = new DataSource({
|
||
type: 'postgres',
|
||
url: cfg.postgresUrl,
|
||
entities: [SubgraphRegistryEntity],
|
||
synchronize: true,
|
||
});
|
||
await ds.initialize();
|
||
const repo = ds.getRepository(SubgraphRegistryEntity);
|
||
await repo.upsert(
|
||
{
|
||
packageId: 'core@coopback',
|
||
version: 'monolith',
|
||
url: cfg.coreSubgraphUrl,
|
||
active: true,
|
||
healthStatus: 'unknown',
|
||
},
|
||
['packageId'],
|
||
);
|
||
await ds.destroy();
|
||
}
|
||
|
||
async function bootstrap() {
|
||
const cfg = loadAppConfig();
|
||
await seedCoreSubgraph(cfg);
|
||
|
||
const app = await NestFactory.create(AppModule);
|
||
await app.listen(cfg.port);
|
||
// eslint-disable-next-line no-console
|
||
console.log(
|
||
`[orchestrator] up at :${cfg.port} ` +
|
||
`(coopname=${cfg.coopname}, core=${cfg.coreSubgraphUrl})`,
|
||
);
|
||
}
|
||
|
||
bootstrap().catch((err) => {
|
||
// eslint-disable-next-line no-console
|
||
console.error('[orchestrator] failed to bootstrap:', err);
|
||
process.exit(1);
|
||
});
|