Skip to content

Commit

Permalink
feat(server): add app restart api & handler (labring#558)
Browse files Browse the repository at this point in the history
  • Loading branch information
maslow authored Dec 19, 2022
1 parent bdf9c55 commit 5764029
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 4 deletions.
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)
}
}
}
}

0 comments on commit 5764029

Please sign in to comment.