mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-31 04:23:40 +00:00
Feature/restart service (#1554)
* add restart button to service show page and restart rpc api * Feature/restart rpc (#1555) * add restart rpc and status * wire up rpc * add restarting bool Co-authored-by: Aiden McClelland <me@drbonez.dev> * check if service is restarting * filter package when restarting to avoid glitch Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
@@ -268,9 +268,11 @@ async fn perform_backup<Db: DbHandle>(
|
|||||||
|
|
||||||
main_status_model.lock(&mut tx, LockType::Write).await?;
|
main_status_model.lock(&mut tx, LockType::Write).await?;
|
||||||
let (started, health) = match main_status_model.get(&mut tx, true).await?.into_owned() {
|
let (started, health) = match main_status_model.get(&mut tx, true).await?.into_owned() {
|
||||||
MainStatus::Starting => (Some(Utc::now()), Default::default()),
|
MainStatus::Starting { .. } => (Some(Utc::now()), Default::default()),
|
||||||
MainStatus::Running { started, health } => (Some(started), health.clone()),
|
MainStatus::Running { started, health } => (Some(started), health.clone()),
|
||||||
MainStatus::Stopped | MainStatus::Stopping => (None, Default::default()),
|
MainStatus::Stopped | MainStatus::Stopping | MainStatus::Restarting => {
|
||||||
|
(None, Default::default())
|
||||||
|
}
|
||||||
MainStatus::BackingUp { .. } => {
|
MainStatus::BackingUp { .. } => {
|
||||||
backup_report.insert(
|
backup_report.insert(
|
||||||
package_id,
|
package_id,
|
||||||
|
|||||||
@@ -335,12 +335,14 @@ impl RpcContext {
|
|||||||
let main = match status.main {
|
let main = match status.main {
|
||||||
MainStatus::BackingUp { started, .. } => {
|
MainStatus::BackingUp { started, .. } => {
|
||||||
if let Some(_) = started {
|
if let Some(_) = started {
|
||||||
MainStatus::Starting
|
MainStatus::Starting { restarting: false }
|
||||||
} else {
|
} else {
|
||||||
MainStatus::Stopped
|
MainStatus::Stopped
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MainStatus::Running { .. } => MainStatus::Starting,
|
MainStatus::Running { .. } => {
|
||||||
|
MainStatus::Starting { restarting: false }
|
||||||
|
}
|
||||||
a => a.clone(),
|
a => a.clone(),
|
||||||
};
|
};
|
||||||
let new_package = PackageDataEntry::Installed {
|
let new_package = PackageDataEntry::Installed {
|
||||||
|
|||||||
@@ -71,7 +71,10 @@ pub async fn start(
|
|||||||
let mut tx = db.begin().await?;
|
let mut tx = db.begin().await?;
|
||||||
let receipts = StartReceipts::new(&mut tx, &id).await?;
|
let receipts = StartReceipts::new(&mut tx, &id).await?;
|
||||||
let version = receipts.version.get(&mut tx).await?;
|
let version = receipts.version.get(&mut tx).await?;
|
||||||
receipts.status.set(&mut tx, MainStatus::Starting).await?;
|
receipts
|
||||||
|
.status
|
||||||
|
.set(&mut tx, MainStatus::Starting { restarting: false })
|
||||||
|
.await?;
|
||||||
heal_all_dependents_transitive(&ctx, &mut tx, &id, &receipts.dependency_receipt).await?;
|
heal_all_dependents_transitive(&ctx, &mut tx, &id, &receipts.dependency_receipt).await?;
|
||||||
|
|
||||||
let revision = tx.commit(None).await?;
|
let revision = tx.commit(None).await?;
|
||||||
@@ -181,3 +184,33 @@ pub async fn stop_impl(ctx: RpcContext, id: PackageId) -> Result<WithRevision<()
|
|||||||
response: (),
|
response: (),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[command(display(display_none))]
|
||||||
|
pub async fn restart(
|
||||||
|
#[context] ctx: RpcContext,
|
||||||
|
#[arg] id: PackageId,
|
||||||
|
) -> Result<WithRevision<()>, Error> {
|
||||||
|
let mut db = ctx.db.handle();
|
||||||
|
let mut tx = db.begin().await?;
|
||||||
|
|
||||||
|
let mut status = crate::db::DatabaseModel::new()
|
||||||
|
.package_data()
|
||||||
|
.idx_model(&id)
|
||||||
|
.and_then(|pde| pde.installed())
|
||||||
|
.map(|i| i.status().main())
|
||||||
|
.get_mut(&mut tx)
|
||||||
|
.await?;
|
||||||
|
if !matches!(&*status, Some(MainStatus::Running { .. })) {
|
||||||
|
return Err(Error::new(
|
||||||
|
eyre!("{} is not running", id),
|
||||||
|
crate::ErrorKind::InvalidRequest,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
*status = Some(MainStatus::Restarting);
|
||||||
|
status.save(&mut tx).await?;
|
||||||
|
|
||||||
|
Ok(WithRevision {
|
||||||
|
revision: tx.commit(None).await?,
|
||||||
|
response: (),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ use rpc_toolkit::command;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
|
use crate::config::action::{ConfigActions, ConfigRes};
|
||||||
use crate::config::spec::PackagePointerSpec;
|
use crate::config::spec::PackagePointerSpec;
|
||||||
use crate::config::{not_found, Config, ConfigReceipts, ConfigSpec};
|
use crate::config::{not_found, Config, ConfigReceipts, ConfigSpec};
|
||||||
use crate::context::RpcContext;
|
use crate::context::RpcContext;
|
||||||
use crate::db::model::{CurrentDependencies, CurrentDependents, InstalledPackageDataEntry};
|
use crate::db::model::{CurrentDependencies, CurrentDependents, InstalledPackageDataEntry};
|
||||||
use crate::procedure::{NoOutput, PackageProcedure};
|
use crate::procedure::{NoOutput, PackageProcedure, ProcedureName};
|
||||||
use crate::s9pk::manifest::{Manifest, PackageId};
|
use crate::s9pk::manifest::{Manifest, PackageId};
|
||||||
use crate::status::health_check::{HealthCheckId, HealthCheckResult};
|
use crate::status::health_check::{HealthCheckId, HealthCheckResult};
|
||||||
use crate::status::{MainStatus, Status};
|
use crate::status::{MainStatus, Status};
|
||||||
@@ -26,10 +27,6 @@ use crate::util::serde::display_serializable;
|
|||||||
use crate::util::{display_none, Version};
|
use crate::util::{display_none, Version};
|
||||||
use crate::volume::Volumes;
|
use crate::volume::Volumes;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use crate::{
|
|
||||||
config::action::{ConfigActions, ConfigRes},
|
|
||||||
procedure::ProcedureName,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[command(subcommands(configure))]
|
#[command(subcommands(configure))]
|
||||||
pub fn dependency() -> Result<(), Error> {
|
pub fn dependency() -> Result<(), Error> {
|
||||||
@@ -339,7 +336,7 @@ impl DependencyError {
|
|||||||
.await?
|
.await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MainStatus::Starting => {
|
MainStatus::Starting { .. } | MainStatus::Restarting => {
|
||||||
DependencyError::Transitive
|
DependencyError::Transitive
|
||||||
.try_heal(
|
.try_heal(
|
||||||
ctx,
|
ctx,
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ pub fn server() -> Result<(), RpcError> {
|
|||||||
config::config,
|
config::config,
|
||||||
control::start,
|
control::start,
|
||||||
control::stop,
|
control::stop,
|
||||||
|
control::restart,
|
||||||
logs::logs,
|
logs::logs,
|
||||||
properties::properties,
|
properties::properties,
|
||||||
dependencies::dependency,
|
dependencies::dependency,
|
||||||
|
|||||||
@@ -31,7 +31,10 @@ async fn synchronize_once(shared: &ManagerSharedState) -> Result<Status, Error>
|
|||||||
MainStatus::Stopping => {
|
MainStatus::Stopping => {
|
||||||
*status = MainStatus::Stopped;
|
*status = MainStatus::Stopped;
|
||||||
}
|
}
|
||||||
MainStatus::Starting => {
|
MainStatus::Restarting => {
|
||||||
|
*status = MainStatus::Starting { restarting: true };
|
||||||
|
}
|
||||||
|
MainStatus::Starting { .. } => {
|
||||||
start(shared).await?;
|
start(shared).await?;
|
||||||
}
|
}
|
||||||
MainStatus::Running { started, .. } => {
|
MainStatus::Running { started, .. } => {
|
||||||
@@ -41,19 +44,19 @@ async fn synchronize_once(shared: &ManagerSharedState) -> Result<Status, Error>
|
|||||||
MainStatus::BackingUp { .. } => (),
|
MainStatus::BackingUp { .. } => (),
|
||||||
},
|
},
|
||||||
Status::Starting => match *status {
|
Status::Starting => match *status {
|
||||||
MainStatus::Stopped | MainStatus::Stopping => {
|
MainStatus::Stopped | MainStatus::Stopping | MainStatus::Restarting => {
|
||||||
stop(shared).await?;
|
stop(shared).await?;
|
||||||
}
|
}
|
||||||
MainStatus::Starting | MainStatus::Running { .. } => (),
|
MainStatus::Starting { .. } | MainStatus::Running { .. } => (),
|
||||||
MainStatus::BackingUp { .. } => {
|
MainStatus::BackingUp { .. } => {
|
||||||
pause(shared).await?;
|
pause(shared).await?;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Status::Running => match *status {
|
Status::Running => match *status {
|
||||||
MainStatus::Stopped | MainStatus::Stopping => {
|
MainStatus::Stopped | MainStatus::Stopping | MainStatus::Restarting => {
|
||||||
stop(shared).await?;
|
stop(shared).await?;
|
||||||
}
|
}
|
||||||
MainStatus::Starting => {
|
MainStatus::Starting { .. } => {
|
||||||
*status = MainStatus::Running {
|
*status = MainStatus::Running {
|
||||||
started: Utc::now(),
|
started: Utc::now(),
|
||||||
health: BTreeMap::new(),
|
health: BTreeMap::new(),
|
||||||
@@ -65,10 +68,10 @@ async fn synchronize_once(shared: &ManagerSharedState) -> Result<Status, Error>
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Status::Paused => match *status {
|
Status::Paused => match *status {
|
||||||
MainStatus::Stopped | MainStatus::Stopping => {
|
MainStatus::Stopped | MainStatus::Stopping | MainStatus::Restarting => {
|
||||||
stop(shared).await?;
|
stop(shared).await?;
|
||||||
}
|
}
|
||||||
MainStatus::Starting | MainStatus::Running { .. } => {
|
MainStatus::Starting { .. } | MainStatus::Running { .. } => {
|
||||||
resume(shared).await?;
|
resume(shared).await?;
|
||||||
}
|
}
|
||||||
MainStatus::BackingUp { .. } => (),
|
MainStatus::BackingUp { .. } => (),
|
||||||
|
|||||||
@@ -24,8 +24,11 @@ pub struct Status {
|
|||||||
#[serde(rename_all = "kebab-case")]
|
#[serde(rename_all = "kebab-case")]
|
||||||
pub enum MainStatus {
|
pub enum MainStatus {
|
||||||
Stopped,
|
Stopped,
|
||||||
|
Restarting,
|
||||||
Stopping,
|
Stopping,
|
||||||
Starting,
|
Starting {
|
||||||
|
restarting: bool,
|
||||||
|
},
|
||||||
Running {
|
Running {
|
||||||
started: DateTime<Utc>,
|
started: DateTime<Utc>,
|
||||||
health: BTreeMap<HealthCheckId, HealthCheckResult>,
|
health: BTreeMap<HealthCheckId, HealthCheckResult>,
|
||||||
@@ -38,25 +41,26 @@ pub enum MainStatus {
|
|||||||
impl MainStatus {
|
impl MainStatus {
|
||||||
pub fn running(&self) -> bool {
|
pub fn running(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
MainStatus::Starting
|
MainStatus::Starting { .. }
|
||||||
| MainStatus::Running { .. }
|
| MainStatus::Running { .. }
|
||||||
| MainStatus::BackingUp {
|
| MainStatus::BackingUp {
|
||||||
started: Some(_), ..
|
started: Some(_), ..
|
||||||
} => true,
|
} => true,
|
||||||
MainStatus::Stopped
|
MainStatus::Stopped
|
||||||
| MainStatus::Stopping
|
| MainStatus::Stopping
|
||||||
|
| MainStatus::Restarting
|
||||||
| MainStatus::BackingUp { started: None, .. } => false,
|
| MainStatus::BackingUp { started: None, .. } => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn stop(&mut self) {
|
pub fn stop(&mut self) {
|
||||||
match self {
|
match self {
|
||||||
MainStatus::Starting | MainStatus::Running { .. } => {
|
MainStatus::Starting { .. } | MainStatus::Running { .. } => {
|
||||||
*self = MainStatus::Stopping;
|
*self = MainStatus::Stopping;
|
||||||
}
|
}
|
||||||
MainStatus::BackingUp { started, .. } => {
|
MainStatus::BackingUp { started, .. } => {
|
||||||
*started = None;
|
*started = None;
|
||||||
}
|
}
|
||||||
MainStatus::Stopped | MainStatus::Stopping => (),
|
MainStatus::Stopped | MainStatus::Stopping | MainStatus::Restarting => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { NavController } from '@ionic/angular'
|
|||||||
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
import { PatchDbService } from 'src/app/services/patch-db/patch-db.service'
|
||||||
import {
|
import {
|
||||||
PackageDataEntry,
|
PackageDataEntry,
|
||||||
|
PackageMainStatus,
|
||||||
PackageState,
|
PackageState,
|
||||||
} from 'src/app/services/patch-db/data-model'
|
} from 'src/app/services/patch-db/data-model'
|
||||||
import {
|
import {
|
||||||
@@ -13,7 +14,7 @@ import {
|
|||||||
ConnectionFailure,
|
ConnectionFailure,
|
||||||
ConnectionService,
|
ConnectionService,
|
||||||
} from 'src/app/services/connection.service'
|
} from 'src/app/services/connection.service'
|
||||||
import { map, startWith } from 'rxjs/operators'
|
import { map, startWith, filter } from 'rxjs/operators'
|
||||||
import { ActivatedRoute } from '@angular/router'
|
import { ActivatedRoute } from '@angular/router'
|
||||||
import { getPkgId } from '@start9labs/shared'
|
import { getPkgId } from '@start9labs/shared'
|
||||||
|
|
||||||
@@ -32,6 +33,13 @@ export class AppShowPage {
|
|||||||
private readonly pkgId = getPkgId(this.route)
|
private readonly pkgId = getPkgId(this.route)
|
||||||
|
|
||||||
readonly pkg$ = this.patch.watch$('package-data', this.pkgId).pipe(
|
readonly pkg$ = this.patch.watch$('package-data', this.pkgId).pipe(
|
||||||
|
filter(
|
||||||
|
(p: PackageDataEntry) =>
|
||||||
|
!(
|
||||||
|
p.installed?.status.main.status === PackageMainStatus.Starting &&
|
||||||
|
p.installed?.status.main.restarting
|
||||||
|
),
|
||||||
|
),
|
||||||
map(pkg => {
|
map(pkg => {
|
||||||
// if package disappears, navigate to list page
|
// if package disappears, navigate to list page
|
||||||
if (!pkg) {
|
if (!pkg) {
|
||||||
|
|||||||
@@ -21,6 +21,14 @@
|
|||||||
<ion-icon slot="start" name="stop-outline"></ion-icon>
|
<ion-icon slot="start" name="stop-outline"></ion-icon>
|
||||||
Stop
|
Stop
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
<ion-button
|
||||||
|
class="action-button"
|
||||||
|
color="warning"
|
||||||
|
(click)="tryRestart()"
|
||||||
|
>
|
||||||
|
<ion-icon slot="start" name="refresh"></ion-icon>
|
||||||
|
Restart
|
||||||
|
</ion-button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ion-button
|
<ion-button
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-button {
|
.action-button {
|
||||||
margin: 20px 20px 10px 0;
|
margin: 12px 20px 10px 0;
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
min-width: 140px;
|
min-width: 140px;
|
||||||
}
|
}
|
||||||
@@ -137,8 +137,6 @@ export class AppShowStatusComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
async tryRestart(): Promise<void> {
|
async tryRestart(): Promise<void> {
|
||||||
if (hasCurrentDeps(this.pkg)) {
|
if (hasCurrentDeps(this.pkg)) {
|
||||||
const alert = await this.alertCtrl.create({
|
const alert = await this.alertCtrl.create({
|
||||||
@@ -165,7 +163,28 @@ export class AppShowStatusComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
>>>>>>> 918a1907... Remove app wiz and dry calls (#1541)
|
async presentAlertRestart(): Promise<void> {
|
||||||
|
const alert = await this.alertCtrl.create({
|
||||||
|
header: 'Confirm',
|
||||||
|
message: 'Are you sure you want to restart this service?',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: 'Cancel',
|
||||||
|
role: 'cancel',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Restart',
|
||||||
|
handler: () => {
|
||||||
|
this.restart()
|
||||||
|
},
|
||||||
|
cssClass: 'enter-click',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await alert.present()
|
||||||
|
}
|
||||||
|
|
||||||
private async start(): Promise<void> {
|
private async start(): Promise<void> {
|
||||||
const loader = await this.loadingCtrl.create({
|
const loader = await this.loadingCtrl.create({
|
||||||
message: `Starting...`,
|
message: `Starting...`,
|
||||||
@@ -181,8 +200,6 @@ export class AppShowStatusComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
private async stop(): Promise<void> {
|
private async stop(): Promise<void> {
|
||||||
const loader = await this.loadingCtrl.create({
|
const loader = await this.loadingCtrl.create({
|
||||||
message: 'Stopping...',
|
message: 'Stopping...',
|
||||||
@@ -212,8 +229,6 @@ export class AppShowStatusComponent {
|
|||||||
loader.dismiss()
|
loader.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
>>>>>>> 918a1907... Remove app wiz and dry calls (#1541)
|
|
||||||
private async presentAlertStart(message: string): Promise<boolean> {
|
private async presentAlertStart(message: string): Promise<boolean> {
|
||||||
return new Promise(async resolve => {
|
return new Promise(async resolve => {
|
||||||
const alert = await this.alertCtrl.create({
|
const alert = await this.alertCtrl.create({
|
||||||
|
|||||||
@@ -215,6 +215,9 @@ export module RR {
|
|||||||
export type StartPackageReq = WithExpire<{ id: string }> // package.start
|
export type StartPackageReq = WithExpire<{ id: string }> // package.start
|
||||||
export type StartPackageRes = WithRevision<null>
|
export type StartPackageRes = WithRevision<null>
|
||||||
|
|
||||||
|
export type RestartPackageReq = WithExpire<{ id: string }> // package.restart
|
||||||
|
export type RestartPackageRes = WithRevision<null>
|
||||||
|
|
||||||
export type StopPackageReq = WithExpire<{ id: string }> // package.stop
|
export type StopPackageReq = WithExpire<{ id: string }> // package.stop
|
||||||
export type StopPackageRes = WithRevision<null>
|
export type StopPackageRes = WithRevision<null>
|
||||||
|
|
||||||
|
|||||||
@@ -233,6 +233,12 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
|
|||||||
startPackage = (params: RR.StartPackageReq) =>
|
startPackage = (params: RR.StartPackageReq) =>
|
||||||
this.syncResponse(() => this.startPackageRaw(params))()
|
this.syncResponse(() => this.startPackageRaw(params))()
|
||||||
|
|
||||||
|
protected abstract restartPackageRaw(
|
||||||
|
params: RR.RestartPackageReq,
|
||||||
|
): Promise<RR.RestartPackageRes>
|
||||||
|
restartPackage = (params: RR.RestartPackageReq) =>
|
||||||
|
this.syncResponse(() => this.restartPackageRaw(params))()
|
||||||
|
|
||||||
protected abstract stopPackageRaw(
|
protected abstract stopPackageRaw(
|
||||||
params: RR.StopPackageReq,
|
params: RR.StopPackageReq,
|
||||||
): Promise<RR.StopPackageRes>
|
): Promise<RR.StopPackageRes>
|
||||||
|
|||||||
@@ -306,6 +306,12 @@ export class LiveApiService extends ApiService {
|
|||||||
return this.http.rpcRequest({ method: 'package.start', params })
|
return this.http.rpcRequest({ method: 'package.start', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async restartPackageRaw(
|
||||||
|
params: RR.RestartPackageReq,
|
||||||
|
): Promise<RR.RestartPackageRes> {
|
||||||
|
return this.http.rpcRequest({ method: 'package.restart', params })
|
||||||
|
}
|
||||||
|
|
||||||
async stopPackageRaw(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
async stopPackageRaw(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||||
return this.http.rpcRequest({ method: 'package.stop', params })
|
return this.http.rpcRequest({ method: 'package.stop', params })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export class MockApiService extends ApiService {
|
|||||||
value: mockPatchData,
|
value: mockPatchData,
|
||||||
expireId: null,
|
expireId: null,
|
||||||
})
|
})
|
||||||
private readonly revertTime = 4000
|
private readonly revertTime = 2000
|
||||||
sequence: number
|
sequence: number
|
||||||
|
|
||||||
constructor(private readonly bootstrapper: LocalStorageBootstrap) {
|
constructor(private readonly bootstrapper: LocalStorageBootstrap) {
|
||||||
@@ -654,6 +654,63 @@ export class MockApiService extends ApiService {
|
|||||||
return this.withRevision(originalPatch)
|
return this.withRevision(originalPatch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async restartPackageRaw(
|
||||||
|
params: RR.RestartPackageReq,
|
||||||
|
): Promise<RR.RestartPackageRes> {
|
||||||
|
// first enact stop
|
||||||
|
await pauseFor(2000)
|
||||||
|
const path = `/package-data/${params.id}/installed/status/main`
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const patch2 = [
|
||||||
|
{
|
||||||
|
op: PatchOp.REPLACE,
|
||||||
|
path: path + '/status',
|
||||||
|
value: PackageMainStatus.Running,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: PatchOp.REPLACE,
|
||||||
|
path: path + '/health',
|
||||||
|
value: {
|
||||||
|
'ephemeral-health-check': {
|
||||||
|
result: 'starting',
|
||||||
|
},
|
||||||
|
'unnecessary-health-check': {
|
||||||
|
result: 'disabled',
|
||||||
|
},
|
||||||
|
'chain-state': {
|
||||||
|
result: 'loading',
|
||||||
|
message: 'Bitcoin is syncing from genesis',
|
||||||
|
},
|
||||||
|
'p2p-interface': {
|
||||||
|
result: 'success',
|
||||||
|
},
|
||||||
|
'rpc-interface': {
|
||||||
|
result: 'failure',
|
||||||
|
error: 'RPC interface unreachable.',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as any,
|
||||||
|
]
|
||||||
|
this.updateMock(patch2)
|
||||||
|
}, this.revertTime)
|
||||||
|
|
||||||
|
const patch = [
|
||||||
|
{
|
||||||
|
op: PatchOp.REPLACE,
|
||||||
|
path: path + '/status',
|
||||||
|
value: PackageMainStatus.Restarting,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: PatchOp.REPLACE,
|
||||||
|
path: path + '/health',
|
||||||
|
value: {},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return this.withRevision(patch)
|
||||||
|
}
|
||||||
|
|
||||||
async stopPackageRaw(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
async stopPackageRaw(params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
||||||
await pauseFor(2000)
|
await pauseFor(2000)
|
||||||
const path = `/package-data/${params.id}/installed/status/main`
|
const path = `/package-data/${params.id}/installed/status/main`
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ export type MainStatus =
|
|||||||
| MainStatusStarting
|
| MainStatusStarting
|
||||||
| MainStatusRunning
|
| MainStatusRunning
|
||||||
| MainStatusBackingUp
|
| MainStatusBackingUp
|
||||||
|
| MainStatusRestarting
|
||||||
|
|
||||||
export interface MainStatusStopped {
|
export interface MainStatusStopped {
|
||||||
status: PackageMainStatus.Stopped
|
status: PackageMainStatus.Stopped
|
||||||
@@ -261,6 +262,7 @@ export interface MainStatusStopping {
|
|||||||
|
|
||||||
export interface MainStatusStarting {
|
export interface MainStatusStarting {
|
||||||
status: PackageMainStatus.Starting
|
status: PackageMainStatus.Starting
|
||||||
|
restarting: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MainStatusRunning {
|
export interface MainStatusRunning {
|
||||||
@@ -274,12 +276,17 @@ export interface MainStatusBackingUp {
|
|||||||
started: string | null // UTC date string
|
started: string | null // UTC date string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface MainStatusRestarting {
|
||||||
|
status: PackageMainStatus.Restarting
|
||||||
|
}
|
||||||
|
|
||||||
export enum PackageMainStatus {
|
export enum PackageMainStatus {
|
||||||
Starting = 'starting',
|
Starting = 'starting',
|
||||||
Running = 'running',
|
Running = 'running',
|
||||||
Stopping = 'stopping',
|
Stopping = 'stopping',
|
||||||
Stopped = 'stopped',
|
Stopped = 'stopped',
|
||||||
BackingUp = 'backing-up',
|
BackingUp = 'backing-up',
|
||||||
|
Restarting = 'restarting',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HealthCheckResult =
|
export type HealthCheckResult =
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { isEmptyObject } from '@start9labs/shared'
|
import { isEmptyObject } from '@start9labs/shared'
|
||||||
import {
|
import {
|
||||||
|
MainStatusStarting,
|
||||||
PackageDataEntry,
|
PackageDataEntry,
|
||||||
PackageMainStatus,
|
PackageMainStatus,
|
||||||
PackageState,
|
PackageState,
|
||||||
@@ -32,6 +33,8 @@ export function renderPkgStatus(pkg: PackageDataEntry): PackageStatus {
|
|||||||
function getPrimaryStatus(status: Status): PrimaryStatus {
|
function getPrimaryStatus(status: Status): PrimaryStatus {
|
||||||
if (!status.configured) {
|
if (!status.configured) {
|
||||||
return PrimaryStatus.NeedsConfig
|
return PrimaryStatus.NeedsConfig
|
||||||
|
} else if ((status.main as MainStatusStarting).restarting) {
|
||||||
|
return PrimaryStatus.Restarting
|
||||||
} else {
|
} else {
|
||||||
return status.main.status as any as PrimaryStatus
|
return status.main.status as any as PrimaryStatus
|
||||||
}
|
}
|
||||||
@@ -57,7 +60,6 @@ function getHealthStatus(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const values = Object.values(status.main.health)
|
const values = Object.values(status.main.health)
|
||||||
console.log('HEALTH CHECKS', values)
|
|
||||||
|
|
||||||
if (values.some(h => h.result === 'failure')) {
|
if (values.some(h => h.result === 'failure')) {
|
||||||
return HealthStatus.Failure
|
return HealthStatus.Failure
|
||||||
@@ -94,6 +96,7 @@ export enum PrimaryStatus {
|
|||||||
Starting = 'starting',
|
Starting = 'starting',
|
||||||
Running = 'running',
|
Running = 'running',
|
||||||
Stopping = 'stopping',
|
Stopping = 'stopping',
|
||||||
|
Restarting = 'restarting',
|
||||||
Stopped = 'stopped',
|
Stopped = 'stopped',
|
||||||
BackingUp = 'backing-up',
|
BackingUp = 'backing-up',
|
||||||
// config
|
// config
|
||||||
@@ -139,6 +142,11 @@ export const PrimaryRendering: Record<string, StatusRendering> = {
|
|||||||
color: 'dark-shade',
|
color: 'dark-shade',
|
||||||
showDots: true,
|
showDots: true,
|
||||||
},
|
},
|
||||||
|
[PrimaryStatus.Restarting]: {
|
||||||
|
display: 'Restarting',
|
||||||
|
color: 'warning',
|
||||||
|
showDots: true,
|
||||||
|
},
|
||||||
[PrimaryStatus.Stopped]: {
|
[PrimaryStatus.Stopped]: {
|
||||||
display: 'Stopped',
|
display: 'Stopped',
|
||||||
color: 'dark-shade',
|
color: 'dark-shade',
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::pin::Pin;
|
||||||
|
use std::sync::Arc;
|
||||||
use deno_core::anyhow::{anyhow, bail};
|
use deno_core::anyhow::{anyhow, bail};
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::resolve_import;
|
use deno_core::{
|
||||||
use deno_core::JsRuntime;
|
resolve_import, Extension, JsRuntime, ModuleLoader, ModuleSource, ModuleSourceFuture,
|
||||||
use deno_core::ModuleLoader;
|
ModuleSpecifier, ModuleType, OpDecl, RuntimeOptions, Snapshot,
|
||||||
use deno_core::ModuleSource;
|
};
|
||||||
use deno_core::ModuleSourceFuture;
|
use helpers::{script_dir, NonDetachingJoinHandle};
|
||||||
use deno_core::ModuleSpecifier;
|
|
||||||
use deno_core::ModuleType;
|
|
||||||
use deno_core::RuntimeOptions;
|
|
||||||
use deno_core::Snapshot;
|
|
||||||
use deno_core::{Extension, OpDecl};
|
|
||||||
use helpers::script_dir;
|
|
||||||
use helpers::NonDetachingJoinHandle;
|
|
||||||
use models::{PackageId, ProcedureName, Version, VolumeId};
|
use models::{PackageId, ProcedureName, Version, VolumeId};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
use std::{path::Path, sync::Arc};
|
|
||||||
use std::{path::PathBuf, pin::Pin};
|
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
pub trait PathForVolumeId: Send + Sync {
|
pub trait PathForVolumeId: Send + Sync {
|
||||||
@@ -335,23 +329,17 @@ impl JsExecutionEnvironment {
|
|||||||
|
|
||||||
/// Note: Make sure that we have the assumption that all these methods are callable at any time, and all call restrictions should be in rust
|
/// Note: Make sure that we have the assumption that all these methods are callable at any time, and all call restrictions should be in rust
|
||||||
mod fns {
|
mod fns {
|
||||||
use deno_core::{
|
use std::cell::RefCell;
|
||||||
anyhow::{anyhow, bail},
|
use std::convert::TryFrom;
|
||||||
error::AnyError,
|
use std::path::{Path, PathBuf};
|
||||||
*,
|
use std::rc::Rc;
|
||||||
};
|
use deno_core::anyhow::{anyhow, bail};
|
||||||
|
use deno_core::error::AnyError;
|
||||||
|
use deno_core::*;
|
||||||
|
use models::VolumeId;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
use std::{
|
|
||||||
cell::RefCell,
|
|
||||||
convert::TryFrom,
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use models::VolumeId;
|
|
||||||
|
|
||||||
use crate::{system_time_as_unix_ms, MetadataJs};
|
use crate::{system_time_as_unix_ms, MetadataJs};
|
||||||
|
|
||||||
use super::{AnswerState, JsContext};
|
use super::{AnswerState, JsContext};
|
||||||
|
|||||||
Reference in New Issue
Block a user