achieve clean shutdown, no open handles

This commit is contained in:
Ladd Hoffman 2025-01-02 14:43:32 -06:00
parent 58c5f5dc4e
commit b147378bf8
11 changed files with 45 additions and 34 deletions

View File

@ -69,6 +69,7 @@ export DEBUG="*,-express:*"
export RHIZOME_REQUEST_BIND_PORT=4000
export RHIZOME_PUBLISH_BIND_PORT=4001
export RHIZOME_SEED_PEERS='localhost:4002, localhost:4004'
export RHIZOME_HTTP_API_ENABLE=true
export RHIZOME_HTTP_API_PORT=3000
export RHIZOME_PEER_ID=peer1
export RHIZOME_PUB_SUB_TOPIC=rhizome-demo-1
@ -80,6 +81,7 @@ export DEBUG="*,-express:*"
export RHIZOME_REQUEST_BIND_PORT=4002
export RHIZOME_PUBLISH_BIND_PORT=4003
export RHIZOME_SEED_PEERS='localhost:4000, localhost:4004'
export RHIZOME_HTTP_API_ENABLE=true
export RHIZOME_HTTP_API_PORT=3001
export RHIZOME_PEER_ID=peer2
export RHIZOME_PUB_SUB_TOPIC=rhizome-demo-1
@ -91,6 +93,7 @@ export DEBUG="*,-express:*"
export RHIZOME_REQUEST_BIND_PORT=4004
export RHIZOME_PUBLISH_BIND_PORT=4005
export RHIZOME_SEED_PEERS='localhost:4000, localhost:4002'
export RHIZOME_HTTP_API_ENABLE=true
export RHIZOME_HTTP_API_PORT=3002
export RHIZOME_PEER_ID=peer3
export RHIZOME_PUB_SUB_TOPIC=rhizome-demo-1

View File

@ -2,7 +2,6 @@
"name": "rhizome-node",
"version": "0.1.0",
"description": "Rhizomatic database engine node",
"type": "module",
"scripts": {
"build": "tsc",
"build:watch": "tsc --watch",

View File

@ -12,7 +12,6 @@ enum Decision {
};
export class DeltaStream {
rhizomeNode: RhizomeNode;
deltaStream = new EventEmitter();
deltasProposed: Delta[] = [];
deltasAccepted: Delta[] = [];
@ -20,9 +19,7 @@ export class DeltaStream {
deltasDeferred: Delta[] = [];
hashesReceived = new Set<string>();
constructor(rhizomeNode: RhizomeNode) {
this.rhizomeNode = rhizomeNode;
}
constructor(readonly rhizomeNode: RhizomeNode) {}
applyPolicy(delta: Delta): Decision {
return !!delta && Decision.Accept;

View File

@ -9,12 +9,6 @@ export class HttpHtml {
constructor(readonly rhizomeNode: RhizomeNode) {
this.mdFiles = new MDFiles(this.rhizomeNode);
// Scan and watch for markdown files
this.mdFiles.readDir();
this.mdFiles.readReadme();
this.mdFiles.watchDir();
this.mdFiles.watchReadme();
// Serve README
this.router.get('/README', (_req: express.Request, res: express.Response) => {
const html = this.mdFiles.getReadmeHTML();
@ -39,7 +33,15 @@ export class HttpHtml {
});
}
close() {
this.mdFiles.close();
start() {
// Scan and watch for markdown files
this.mdFiles.readDir();
this.mdFiles.readReadme();
this.mdFiles.watchDir();
this.mdFiles.watchReadme();
}
stop() {
this.mdFiles.stop();
}
}

View File

@ -23,6 +23,7 @@ export class HttpServer {
start() {
const {httpAddr, httpPort} = this.rhizomeNode.config;
this.httpHtml.start();
this.server = this.app.listen({
port: httpPort,
host: httpAddr,
@ -34,6 +35,6 @@ export class HttpServer {
async stop() {
this.server?.close();
this.httpHtml.close();
this.httpHtml.stop();
}
}

View File

@ -122,9 +122,7 @@ export class Lossless {
}
viewSpecific(entityId: DomainEntityID, deltaIds: DeltaID[], deltaFilter?: DeltaFilter): LosslessViewOne | undefined {
debug(`[${this.rhizomeNode.config.peerId}]`, `viewSpecific, deltaIds:`, JSON.stringify(deltaIds));
const combinedFilter = (delta: Delta) => {
debug(`[${this.rhizomeNode.config.peerId}]`, `combinedFilter, deltaIds:`, JSON.stringify(deltaIds));
if (!deltaIds.includes(delta.id)) {
debug(`[${this.rhizomeNode.config.peerId}]`, `Excluding delta ${delta.id} because it's not in the requested list of deltas`);
return false;
@ -191,7 +189,6 @@ export class Lossless {
};
}
debug(`[${this.rhizomeNode.config.peerId}]`, `Returning view:`, JSON.stringify(view, null, 2));
return view;
}

View File

@ -1,6 +1,6 @@
import Debug from 'debug';
import {CREATOR, HTTP_API_ADDR, HTTP_API_ENABLE, HTTP_API_PORT, PEER_ID, PUBLISH_BIND_ADDR, PUBLISH_BIND_HOST, PUBLISH_BIND_PORT, REQUEST_BIND_ADDR, REQUEST_BIND_HOST, REQUEST_BIND_PORT, SEED_PEERS} from './config';
import {DeltaStream} from './deltas';
import {DeltaStream} from './delta-stream';
import {HttpServer} from './http/index';
import {Lossless} from './lossless';
import {parseAddressList, PeerAddress, Peers} from './peers';

View File

@ -69,10 +69,12 @@ class Peer {
async subscribeDeltas() {
if (!this.publishAddr) {
debug(`[${this.rhizomeNode.config.peerId}]`, `Requesting publish addr from peer ${this.reqAddr.toAddrString()}`);
debug(`[${this.rhizomeNode.config.peerId}]`,
`Requesting publish addr from peer ${this.reqAddr.toAddrString()}`);
const res = await this.request(RequestMethods.GetPublishAddress);
this.publishAddr = PeerAddress.fromString(res.toString());
debug(`[${this.rhizomeNode.config.peerId}]`, `Received publish addr ${this.publishAddr.toAddrString()} from peer ${this.reqAddr.toAddrString()}`);
debug(`[${this.rhizomeNode.config.peerId}]`,
`Received publish addr ${this.publishAddr.toAddrString()} from peer ${this.reqAddr.toAddrString()}`);
}
debug(`[${this.rhizomeNode.config.peerId}]`, `Subscribing to peer ${this.reqAddr.toAddrString()}`);

View File

@ -12,15 +12,18 @@ export type PeerRequest = {
export type RequestHandler = (req: PeerRequest, res: ResponseSocket) => void;
export class RequestSocket {
sock = new Request();
sock?: Request;
addrStr: string;
constructor(readonly requestReply: RequestReply, addr: PeerAddress) {
const addrStr = `tcp://${addr.addr}:${addr.port}`;
this.sock.connect(addrStr);
debug(`[${this.requestReply.rhizomeNode.config.peerId}]`, `Request socket connecting to ${addrStr}`);
this.addrStr = `tcp://${addr.addr}:${addr.port}`;
this.sock = new Request();
this.sock.connect(this.addrStr);
debug(`[${this.requestReply.rhizomeNode.config.peerId}]`, `Request socket connecting to ${this.addrStr}`);
}
async request(method: RequestMethods): Promise<Message> {
if (!this.sock) throw new Error('Request socket is undefined');
const req: PeerRequest = {
method
};
@ -34,7 +37,9 @@ export class RequestSocket {
}
close() {
this.sock.close();
this.sock?.close();
// Make sure it goes out of scope
this.sock = undefined;
debug(`[${this.requestReply.rhizomeNode.config.peerId}]`, 'Request socket closed');
}
}
@ -63,7 +68,7 @@ function peerRequestFromMsg(msg: Message): PeerRequest | null {
export class RequestReply {
rhizomeNode: RhizomeNode;
replySock = new Reply();
replySock?: Reply;
requestStream = new EventEmitter();
requestBindAddrStr: string;
@ -75,6 +80,7 @@ export class RequestReply {
// Listen for incoming requests
async start() {
this.replySock = new Reply();
await this.replySock.bind(this.requestBindAddrStr);
debug(`[${this.rhizomeNode.config.peerId}]`, `Reply socket bound to ${this.requestBindAddrStr}`);
@ -90,8 +96,10 @@ export class RequestReply {
// Each handler will get a copy of every message.
registerRequestHandler(handler: RequestHandler) {
this.requestStream.on('request', (req) => {
const res = new ResponseSocket(this.replySock);
handler(req, res);
if (this.replySock) {
const res = new ResponseSocket(this.replySock);
handler(req, res);
}
});
}
@ -100,9 +108,11 @@ export class RequestReply {
}
async stop() {
await this.replySock.unbind(this.requestBindAddrStr);
this.replySock.close();
this.replySock = new Reply();
debug(`[${this.rhizomeNode.config.peerId}]`, 'Reply socket closed');
if (this.replySock) {
await this.replySock.unbind(this.requestBindAddrStr);
this.replySock.close();
this.replySock = undefined;
debug(`[${this.rhizomeNode.config.peerId}]`, 'Reply socket closed');
}
}
}

View File

@ -130,7 +130,7 @@ export class MDFiles {
});
}
close() {
stop() {
this.dirWatcher?.close();
this.readmeWatcher?.close();
}

View File

@ -4,7 +4,7 @@
"module": "CommonJS",
"esModuleInterop": true,
"moduleResolution": "Node",
"sourceMap": false,
"sourceMap": true,
"baseUrl": ".",
"outDir": "dist",
"importsNotUsedAsValues": "remove",