Commit 52b26878 authored by Will Cory's avatar Will Cory Committed by GitHub

feat(BaseServiceV2):End immediately when looping (#2731)

* end immediately when looping

* changeset

* improvements based on comments

* add logging

* add logging ect. to main loop

* stop main loop

* get rid of this.running for this.loop

* Revert "get rid of this.running for this.loop"

This reverts commit 18e6fe88c61eb154bc76418b0bf39914438d57a5.

* lower-case
Co-authored-by: default avatarWill Cory <willcory@Wills-MacBook-Pro.local>
parent 65a859de
---
'@eth-optimism/common-ts': minor
---
More gracefully shut down base service
...@@ -4,7 +4,6 @@ import Config from 'bcfg' ...@@ -4,7 +4,6 @@ import Config from 'bcfg'
import * as dotenv from 'dotenv' import * as dotenv from 'dotenv'
import { Command, Option } from 'commander' import { Command, Option } from 'commander'
import { ValidatorSpec, Spec, cleanEnv } from 'envalid' import { ValidatorSpec, Spec, cleanEnv } from 'envalid'
import { sleep } from '@eth-optimism/core-utils'
import snakeCase from 'lodash/snakeCase' import snakeCase from 'lodash/snakeCase'
import express, { Router } from 'express' import express, { Router } from 'express'
import prometheus, { Registry } from 'prom-client' import prometheus, { Registry } from 'prom-client'
...@@ -62,6 +61,17 @@ export abstract class BaseServiceV2< ...@@ -62,6 +61,17 @@ export abstract class BaseServiceV2<
TMetrics extends MetricsV2, TMetrics extends MetricsV2,
TServiceState TServiceState
> { > {
/**
* The timeout that controls the polling interval
* If clearTimeout(this.pollingTimeout) is called the timeout will stop
*/
private pollingTimeout: NodeJS.Timeout
/**
* The promise representing this.main
*/
private mainPromise: ReturnType<typeof this.main>
/** /**
* Whether or not the service will loop. * Whether or not the service will loop.
*/ */
...@@ -77,11 +87,6 @@ export abstract class BaseServiceV2< ...@@ -77,11 +87,6 @@ export abstract class BaseServiceV2<
*/ */
protected running: boolean protected running: boolean
/**
* Whether or not the service has run to completion.
*/
protected done: boolean
/** /**
* Whether or not the service is currently healthy. * Whether or not the service is currently healthy.
*/ */
...@@ -373,8 +378,6 @@ export abstract class BaseServiceV2< ...@@ -373,8 +378,6 @@ export abstract class BaseServiceV2<
* main function. Will also catch unhandled errors. * main function. Will also catch unhandled errors.
*/ */
public async run(): Promise<void> { public async run(): Promise<void> {
this.done = false
// Start the app server if not yet running. // Start the app server if not yet running.
if (!this.server) { if (!this.server) {
this.logger.info('starting app server') this.logger.info('starting app server')
...@@ -446,9 +449,11 @@ export abstract class BaseServiceV2< ...@@ -446,9 +449,11 @@ export abstract class BaseServiceV2<
if (this.loop) { if (this.loop) {
this.logger.info('starting main loop') this.logger.info('starting main loop')
this.running = true this.running = true
while (this.running) {
const doLoop = async () => {
try { try {
await this.main() this.mainPromise = this.main()
await this.mainPromise
} catch (err) { } catch (err) {
this.metrics.unhandledErrors.inc() this.metrics.unhandledErrors.inc()
this.logger.error('caught an unhandled exception', { this.logger.error('caught an unhandled exception', {
...@@ -460,15 +465,14 @@ export abstract class BaseServiceV2< ...@@ -460,15 +465,14 @@ export abstract class BaseServiceV2<
// Sleep between loops if we're still running (service not stopped). // Sleep between loops if we're still running (service not stopped).
if (this.running) { if (this.running) {
await sleep(this.loopIntervalMs) this.pollingTimeout = setTimeout(doLoop, this.loopIntervalMs)
} }
} }
doLoop()
} else { } else {
this.logger.info('running main function') this.logger.info('running main function')
await this.main() await this.main()
} }
this.done = true
} }
/** /**
...@@ -476,13 +480,13 @@ export abstract class BaseServiceV2< ...@@ -476,13 +480,13 @@ export abstract class BaseServiceV2<
* iteration is finished and will then stop looping. * iteration is finished and will then stop looping.
*/ */
public async stop(): Promise<void> { public async stop(): Promise<void> {
this.logger.info('stopping main loop...')
this.running = false this.running = false
clearTimeout(this.pollingTimeout)
// Wait until the main loop has finished. this.logger.info('waiting for main to complete')
this.logger.info('stopping service, waiting for main loop to finish') // if main is in the middle of running wait for it to complete
while (!this.done) { await this.mainPromise
await sleep(1000) this.logger.info('main loop stoped.')
}
// Shut down the metrics server if it's running. // Shut down the metrics server if it's running.
if (this.server) { if (this.server) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment