Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): add app restart api & handler #558

Merged
merged 1 commit into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions server/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ model Runtime {
enum ApplicationState {
Running
Stopped
Restarting
}

enum ApplicationPhase {
Expand Down
11 changes: 8 additions & 3 deletions server/src/application/dto/create-application.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import { ApplicationState } from '@prisma/client'
import { IsEnum, IsNotEmpty, Length } from 'class-validator'

enum CreateApplicationState {
Running = 'Running',
Stopped = 'Stopped',
}

export class CreateApplicationDto {
@ApiProperty({ required: true })
@Length(1, 64)
@IsNotEmpty()
name: string

@ApiPropertyOptional({
default: ApplicationState.Running,
enum: ApplicationState,
default: CreateApplicationState.Running,
enum: CreateApplicationState,
})
@IsNotEmpty()
@IsEnum(ApplicationState)
@IsEnum(CreateApplicationState)
state: ApplicationState

@ApiProperty()
Expand Down
6 changes: 5 additions & 1 deletion server/src/application/dto/update-application.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ import { ApiPropertyOptional } from '@nestjs/swagger'
import { ApplicationState } from '@prisma/client'
import { IsIn } from 'class-validator'

const STATES = ['Running', 'Stopped']
const STATES = [
ApplicationState.Running,
ApplicationState.Stopped,
ApplicationState.Restarting,
]
export class UpdateApplicationDto {
/**
* Application name
Expand Down
107 changes: 107 additions & 0 deletions server/src/instance/instance-task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export class InstanceTaskService {
private readonly prisma: PrismaService,
) {}

/**
* State `Running` with phase `Created` or `Stopped` - create instance
*
* -> Phase `Starting`
*/
@Cron(CronExpression.EVERY_SECOND)
async handlePreparedStart() {
const apps = await this.prisma.application.findMany({
Expand Down Expand Up @@ -57,6 +62,11 @@ export class InstanceTaskService {
}
}

/**
* Phase `Starting` - waiting for instance to be available
*
* -> Phase `Started`
*/
@Cron(CronExpression.EVERY_SECOND)
async handleStarting() {
const apps = await this.prisma.application.findMany({
Expand All @@ -78,13 +88,20 @@ export class InstanceTaskService {

if (!instance.service) continue

// if state is `Restarting`, update state to `Running` with phase `Started`
let toState = app.state
if (app.state === ApplicationState.Restarting) {
toState = ApplicationState.Running
}

// update application state
await this.prisma.application.updateMany({
where: {
appid,
phase: ApplicationPhase.Starting,
},
data: {
state: toState,
phase: ApplicationPhase.Started,
},
})
Expand All @@ -95,6 +112,11 @@ export class InstanceTaskService {
}
}

/**
* State `Stopped` with phase `Started` - remove instance
*
* -> Phase `Stopping`
*/
@Cron(CronExpression.EVERY_SECOND)
async handlePreparedStop() {
const apps = await this.prisma.application.findMany({
Expand Down Expand Up @@ -128,6 +150,11 @@ export class InstanceTaskService {
}
}

/**
* Phase `Stopping` - waiting for deployment to be removed.
*
* -> Phase `Stopped`
*/
@Cron(CronExpression.EVERY_SECOND)
async handleStopping() {
const apps = await this.prisma.application.findMany({
Expand Down Expand Up @@ -159,4 +186,84 @@ export class InstanceTaskService {
}
}
}

/**
* State `Restarting` with phase `Started` - remove instance
*
* -> Phase `Stopping`
*/
@Cron(CronExpression.EVERY_SECOND)
async handlePreparedRestart() {
const apps = await this.prisma.application.findMany({
where: {
state: ApplicationState.Restarting,
phase: ApplicationPhase.Started,
},
take: 5,
})

for (const app of apps) {
try {
const appid = app.appid
await this.instanceService.remove(appid)

await this.prisma.application.updateMany({
where: {
appid: app.appid,
state: ApplicationState.Restarting,
phase: ApplicationPhase.Started,
},
data: {
phase: ApplicationPhase.Stopping,
},
})

this.logger.debug(
`Application ${app.appid} updated to phase stopping for restart`,
)
} catch (error) {
this.logger.error(error)
}
}
}

/**
* State `Restarting` with phase `Stopped` - create instance
*
* -> Phase `Starting`
*/
@Cron(CronExpression.EVERY_SECOND)
async handleRestarting() {
const apps = await this.prisma.application.findMany({
where: {
state: ApplicationState.Restarting,
phase: ApplicationPhase.Stopped,
},
take: 5,
})

for (const app of apps) {
try {
const appid = app.appid
await this.instanceService.create(appid)

await this.prisma.application.updateMany({
where: {
appid: app.appid,
state: ApplicationState.Restarting,
phase: ApplicationPhase.Stopped,
},
data: {
phase: ApplicationPhase.Starting,
},
})

this.logger.debug(
`Application ${app.appid} updated to phase starting for restart`,
)
} catch (error) {
this.logger.error(error)
}
}
}
}