mirror of
https://github.com/snowball-tools/snowballtools-base.git
synced 2024-12-22 16:37:44 +00:00
Implement checking for deployment removal records in intervals
This commit is contained in:
parent
4fa6f418ba
commit
f290b5c0b5
@ -436,6 +436,19 @@ export class Database {
|
||||
return Boolean(updateResult.affected);
|
||||
}
|
||||
|
||||
async deleteDeploymentById (deploymentId: string): Promise<boolean> {
|
||||
const deploymentRepository = this.dataSource.getRepository(Deployment);
|
||||
const deployment = await deploymentRepository.findOneOrFail({
|
||||
where: {
|
||||
id: deploymentId
|
||||
}
|
||||
});
|
||||
|
||||
const deleteResult = await deploymentRepository.softRemove(deployment);
|
||||
|
||||
return Boolean(deleteResult);
|
||||
}
|
||||
|
||||
async addProject (user: User, organizationId: string, data: DeepPartial<Project>): Promise<Project> {
|
||||
const projectRepository = this.dataSource.getRepository(Project);
|
||||
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
import { Project } from './Project';
|
||||
import { Domain } from './Domain';
|
||||
import { User } from './User';
|
||||
import { AppDeploymentRecordAttributes } from '../types';
|
||||
import { AppDeploymentRecordAttributes, AppDeploymentRemovalRecordAttributes } from '../types';
|
||||
|
||||
export enum Environment {
|
||||
Production = 'Production',
|
||||
@ -24,6 +24,7 @@ export enum DeploymentStatus {
|
||||
Building = 'Building',
|
||||
Ready = 'Ready',
|
||||
Error = 'Error',
|
||||
Deleting = 'Deleting',
|
||||
}
|
||||
|
||||
export interface ApplicationDeploymentRequest {
|
||||
@ -41,6 +42,12 @@ export interface ApplicationDeploymentRemovalRequest {
|
||||
deployment: string;
|
||||
}
|
||||
|
||||
export interface ApplicationDeploymentRemovalRequest {
|
||||
type: string;
|
||||
version: string;
|
||||
deployment: string;
|
||||
}
|
||||
|
||||
export interface ApplicationRecord {
|
||||
type: string;
|
||||
version: string;
|
||||
@ -104,6 +111,18 @@ export class Deployment {
|
||||
|
||||
@Column('simple-json', { nullable: true })
|
||||
applicationDeploymentRecordData!: AppDeploymentRecordAttributes | null;
|
||||
|
||||
@Column('varchar', { nullable: true })
|
||||
applicationDeploymentRemovalRequestId!: string | null;
|
||||
|
||||
@Column('simple-json', { nullable: true })
|
||||
applicationDeploymentRemovalRequestData!: ApplicationDeploymentRemovalRequest | null;
|
||||
|
||||
@Column('varchar', { nullable: true })
|
||||
applicationDeploymentRemovalRecordId!: string | null;
|
||||
|
||||
@Column('simple-json', { nullable: true })
|
||||
applicationDeploymentRemovalRecordData!: AppDeploymentRemovalRecordAttributes | null;
|
||||
|
||||
@Column({
|
||||
enum: Environment
|
||||
|
@ -12,7 +12,7 @@ import {
|
||||
ApplicationDeploymentRequest,
|
||||
ApplicationDeploymentRemovalRequest
|
||||
} from './entity/Deployment';
|
||||
import { AppDeploymentRecord, PackageJSON } from './types';
|
||||
import { AppDeploymentRecord, AppDeploymentRemovalRecord, PackageJSON } from './types';
|
||||
import { sleep } from './utils';
|
||||
|
||||
const log = debug('snowball:registry');
|
||||
@ -21,6 +21,7 @@ const APP_RECORD_TYPE = 'ApplicationRecord';
|
||||
const APP_DEPLOYMENT_REQUEST_TYPE = 'ApplicationDeploymentRequest';
|
||||
const APP_DEPLOYMENT_REMOVAL_REQUEST_TYPE = 'ApplicationDeploymentRemovalRequest';
|
||||
const APP_DEPLOYMENT_RECORD_TYPE = 'ApplicationDeploymentRecord';
|
||||
const APP_DEPLOYMENT_REMOVAL_RECORD_TYPE = 'ApplicationDeploymentRemovalRecord';
|
||||
const SLEEP_DURATION = 1000;
|
||||
|
||||
// TODO: Move registry code to laconic-sdk/watcher-ts
|
||||
@ -231,6 +232,30 @@ export class Registry {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch ApplicationDeploymentRemovalRecords for deployments
|
||||
*/
|
||||
async getDeploymentRemovalRecords (
|
||||
deployments: Deployment[]
|
||||
): Promise<AppDeploymentRemovalRecord[]> {
|
||||
// Fetch ApplicationDeploymentRemovalRecords for corresponding ApplicationDeploymentRecord set in deployments
|
||||
const records = await this.registry.queryRecords(
|
||||
{
|
||||
type: APP_DEPLOYMENT_REMOVAL_RECORD_TYPE
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
// Filter records with ApplicationDeploymentRecord and ApplicationDeploymentRemovalRequest IDs
|
||||
return records.filter((record: AppDeploymentRemovalRecord) =>
|
||||
deployments.some(
|
||||
(deployment) =>
|
||||
deployment.applicationDeploymentRemovalRequestId === record.attributes.request &&
|
||||
deployment.applicationDeploymentRecordId === record.attributes.deployment
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
async createApplicationDeploymentRemovalRequest (data: {
|
||||
deploymentId: string;
|
||||
}): Promise<{
|
||||
|
@ -15,7 +15,7 @@ import { Permission, ProjectMember } from './entity/ProjectMember';
|
||||
import { User } from './entity/User';
|
||||
import { Registry } from './registry';
|
||||
import { GitHubConfig, RegistryConfig } from './config';
|
||||
import { AppDeploymentRecord, GitPushEventPayload, PackageJSON } from './types';
|
||||
import { AppDeploymentRecord, AppDeploymentRemovalRecord, GitPushEventPayload, PackageJSON } from './types';
|
||||
import { Role } from './entity/UserOrganization';
|
||||
|
||||
const log = debug('snowball:service');
|
||||
@ -63,14 +63,13 @@ export class Service {
|
||||
|
||||
/**
|
||||
* Checks for ApplicationDeploymentRecord and update corresponding deployments
|
||||
* Continues check in loop after a delay of DEPLOY_RECORD_CHECK_DELAY_MS
|
||||
* Continues check in loop after a delay of registryConfig.fetchDeploymentRecordDelay
|
||||
*/
|
||||
async checkDeployRecordsAndUpdate (): Promise<void> {
|
||||
// Fetch deployments in building state
|
||||
const deployments = await this.db.getDeployments({
|
||||
where: {
|
||||
status: DeploymentStatus.Building
|
||||
// TODO: Fetch and check records for recent deployments
|
||||
}
|
||||
});
|
||||
|
||||
@ -116,6 +115,38 @@ export class Service {
|
||||
}, this.config.registryConfig.fetchDeploymentRecordDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for ApplicationDeploymentRemovalRecord and remove corresponding deployments
|
||||
* Continues check in loop after a delay of registryConfig.fetchDeploymentRecordDelay
|
||||
*/
|
||||
async checkDeploymentRemovalRecordsAndUpdate (): Promise<void> {
|
||||
// Fetch deployments in deleting state
|
||||
const deployments = await this.db.getDeployments({
|
||||
where: {
|
||||
status: DeploymentStatus.Deleting
|
||||
}
|
||||
});
|
||||
|
||||
if (deployments.length) {
|
||||
log(
|
||||
`Found ${deployments.length} deployments in ${DeploymentStatus.Deleting} state`
|
||||
);
|
||||
|
||||
// Fetch ApplicationDeploymentRemovalRecords for deployments
|
||||
const records = await this.registry.getDeploymentRemovalRecords(deployments);
|
||||
log(`Found ${records.length} ApplicationDeploymentRemovalRecords`);
|
||||
|
||||
// Update deployments for which ApplicationDeploymentRemovalRecords were returned
|
||||
if (records.length) {
|
||||
await this.deleteDeploymentsWithRecordData(records, deployments);
|
||||
}
|
||||
}
|
||||
|
||||
this.deployRecordCheckTimeout = setTimeout(() => {
|
||||
this.checkDeploymentRemovalRecordsAndUpdate();
|
||||
}, this.config.registryConfig.fetchDeploymentRecordDelay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update deployments with ApplicationDeploymentRecord data
|
||||
*/
|
||||
@ -178,6 +209,45 @@ export class Service {
|
||||
await Promise.all(deploymentUpdatePromises);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete deployments with ApplicationDeploymentRemovalRecord data
|
||||
*/
|
||||
async deleteDeploymentsWithRecordData (
|
||||
records: AppDeploymentRemovalRecord[],
|
||||
deployments: Deployment[],
|
||||
): Promise<void> {
|
||||
const removedApplicationDeploymentRecordIds = records.map(record => record.attributes.deployment);
|
||||
|
||||
// Get removed deployments for ApplicationDeploymentRecords
|
||||
const removedDeployments = deployments.filter(deployment => removedApplicationDeploymentRecordIds.includes(deployment.applicationDeploymentRecordId!))
|
||||
|
||||
const recordToDeploymentsMap = removedDeployments.reduce(
|
||||
(acc: { [key: string]: Deployment }, deployment) => {
|
||||
acc[deployment.applicationDeploymentRecordId!] = deployment;
|
||||
return acc;
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
// Update deployment data for ApplicationDeploymentRecords and delete
|
||||
const deploymentUpdatePromises = records.map(async (record) => {
|
||||
const deployment = recordToDeploymentsMap[record.attributes.deployment];
|
||||
|
||||
await this.db.updateDeploymentById(deployment.id, {
|
||||
applicationDeploymentRemovalRecordId: record.id,
|
||||
applicationDeploymentRemovalRecordData: record.attributes,
|
||||
});
|
||||
|
||||
log(
|
||||
`Updated deployment ${deployment.id} with ApplicationDeploymentRemovalRecord ${record.id}`
|
||||
);
|
||||
|
||||
await this.db.deleteDeploymentById(deployment.id)
|
||||
});
|
||||
|
||||
await Promise.all(deploymentUpdatePromises);
|
||||
}
|
||||
|
||||
async getUser (userId: string): Promise<User | null> {
|
||||
return this.db.getUser({
|
||||
where: {
|
||||
@ -725,10 +795,22 @@ export class Service {
|
||||
id: deploymentId
|
||||
}
|
||||
});
|
||||
|
||||
if (deployment && deployment.applicationDeploymentRecordId) {
|
||||
const result = await this.registry.createApplicationDeploymentRemovalRequest({ deploymentId: deployment.applicationDeploymentRecordId });
|
||||
|
||||
await this.db.updateDeploymentById(
|
||||
deployment.id,
|
||||
{
|
||||
status: DeploymentStatus.Deleting,
|
||||
applicationDeploymentRemovalRequestId: result.applicationDeploymentRemovalRequestId,
|
||||
applicationDeploymentRemovalRequestData: result.applicationDeploymentRemovalRequestData
|
||||
}
|
||||
);
|
||||
|
||||
return (result !== undefined || result !== null);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,13 @@ export interface AppDeploymentRecordAttributes {
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface AppDeploymentRemovalRecordAttributes {
|
||||
deployment: string;
|
||||
request: string;
|
||||
type: "ApplicationDeploymentRemovalRecord";
|
||||
version: string;
|
||||
}
|
||||
|
||||
interface RegistryRecord {
|
||||
id: string;
|
||||
names: string[] | null;
|
||||
@ -50,3 +57,7 @@ interface RegistryRecord {
|
||||
export interface AppDeploymentRecord extends RegistryRecord {
|
||||
attributes: AppDeploymentRecordAttributes;
|
||||
}
|
||||
|
||||
export interface AppDeploymentRemovalRecord extends RegistryRecord {
|
||||
attributes: AppDeploymentRemovalRecordAttributes;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user