Enhance connection handling in DocumentPrinterClient
All checks were successful
farmcontrol/farmcontrol-server/pipeline/head This commit looks good
All checks were successful
farmcontrol/farmcontrol-server/pipeline/head This commit looks good
- Introduced connection state management with `isConnecting` to prevent multiple concurrent connection attempts. - Added `scheduleReconnect` method to handle reconnection logic with a delay. - Improved error handling and logging during connection and reconnection processes. - Updated `updateDocumentPrinterState` to optimize state updates and prevent unnecessary changes.
This commit is contained in:
parent
bb9b472559
commit
d5fe978361
@ -31,6 +31,8 @@ export class DocumentPrinterClient {
|
|||||||
this.state = { type: this.active == true ? "offline" : "inactive" };
|
this.state = { type: this.active == true ? "offline" : "inactive" };
|
||||||
this.isOnline = documentPrinter.online || false;
|
this.isOnline = documentPrinter.online || false;
|
||||||
this.shouldReconnect = true;
|
this.shouldReconnect = true;
|
||||||
|
this.isConnecting = false;
|
||||||
|
this.reconnectTimeout = null;
|
||||||
this.isProcessingQueue = false;
|
this.isProcessingQueue = false;
|
||||||
this.eventUpdateInterval = null;
|
this.eventUpdateInterval = null;
|
||||||
this.initializeInterface();
|
this.initializeInterface();
|
||||||
@ -138,7 +140,37 @@ export class DocumentPrinterClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statesEqual(a, b) {
|
||||||
|
if (!a && !b) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!a || !b) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
a.type === b.type && a.message === b.message && a.progress === b.progress
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleReconnect(delay = 30000) {
|
||||||
|
if (!this.shouldReconnect || this.active === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clearTimeout(this.reconnectTimeout);
|
||||||
|
this.reconnectTimeout = setTimeout(() => {
|
||||||
|
this.reconnectTimeout = null;
|
||||||
|
this.reconnect();
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
async connect() {
|
async connect() {
|
||||||
|
if (this.isConnecting) {
|
||||||
|
logger.debug(
|
||||||
|
`Already connecting to document printer ${this.documentPrinter.name}, skipping`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.active == false) {
|
if (this.active == false) {
|
||||||
this.shouldReconnect = false;
|
this.shouldReconnect = false;
|
||||||
this.isOnline = false;
|
this.isOnline = false;
|
||||||
@ -146,44 +178,58 @@ export class DocumentPrinterClient {
|
|||||||
await this.updateDocumentPrinterState();
|
await this.updateDocumentPrinterState();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
logger.info(
|
|
||||||
`Connecting to document printer ${this.id} (${this.interface})`,
|
|
||||||
);
|
|
||||||
|
|
||||||
clearTimeout(this.reconnectTimeout);
|
this.isConnecting = true;
|
||||||
// Always stop the event update interval when connecting
|
try {
|
||||||
clearInterval(this.eventUpdateInterval);
|
logger.info(
|
||||||
this.eventUpdateInterval = null;
|
`Connecting to document printer ${this.id} (${this.interface})`,
|
||||||
this.state = { type: "connecting", message: null };
|
|
||||||
this.isOnline = false;
|
|
||||||
await this.updateDocumentPrinterState();
|
|
||||||
|
|
||||||
if (!this.printerInterface) {
|
|
||||||
logger.error(
|
|
||||||
`Cannot connect: No interface initialized for ${this.interface}`,
|
|
||||||
);
|
);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.printerInterface.connect();
|
clearTimeout(this.reconnectTimeout);
|
||||||
|
this.reconnectTimeout = null;
|
||||||
if (result.error) {
|
// Always stop the event update interval when connecting
|
||||||
logger.error(
|
clearInterval(this.eventUpdateInterval);
|
||||||
`Error connecting to document printer ${this.documentPrinter.name}:`,
|
this.eventUpdateInterval = null;
|
||||||
result.error,
|
this.state = { type: "connecting", message: null };
|
||||||
);
|
|
||||||
this.isOnline = false;
|
this.isOnline = false;
|
||||||
this.state = { type: "offline", message: result.error };
|
|
||||||
await this.updateDocumentPrinterState();
|
await this.updateDocumentPrinterState();
|
||||||
return false;
|
|
||||||
|
if (!this.printerInterface) {
|
||||||
|
logger.error(
|
||||||
|
`Cannot connect: No interface initialized for ${this.interface}`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await this.printerInterface.connect();
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
logger.error(
|
||||||
|
`Error connecting to document printer ${this.documentPrinter.name}:`,
|
||||||
|
result.error,
|
||||||
|
);
|
||||||
|
this.isOnline = false;
|
||||||
|
this.state = { type: "offline", message: result.error };
|
||||||
|
await this.updateDocumentPrinterState();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logger.info(
|
||||||
|
`Connected to document printer ${this.documentPrinter.name} (${this.interface})`,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
this.isConnecting = false;
|
||||||
}
|
}
|
||||||
logger.info(
|
|
||||||
`Connected to document printer ${this.documentPrinter.name} (${this.interface})`,
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async reconnect() {
|
async reconnect() {
|
||||||
|
if (this.isConnecting) {
|
||||||
|
logger.debug(
|
||||||
|
`Document printer ${this.documentPrinter.name} is already connecting, skipping reconnect`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.active == false) {
|
if (this.active == false) {
|
||||||
logger.info(
|
logger.info(
|
||||||
`Document printer ${this.documentPrinter.name} is inactive, skipping reconnect`,
|
`Document printer ${this.documentPrinter.name} is inactive, skipping reconnect`,
|
||||||
@ -194,6 +240,10 @@ export class DocumentPrinterClient {
|
|||||||
await this.updateDocumentPrinterState();
|
await this.updateDocumentPrinterState();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearTimeout(this.reconnectTimeout);
|
||||||
|
this.reconnectTimeout = null;
|
||||||
|
|
||||||
if (this.isOnline == true) {
|
if (this.isOnline == true) {
|
||||||
logger.info(
|
logger.info(
|
||||||
`Disconnecting from document printer ${this.documentPrinter.name} before reconnecting...`,
|
`Disconnecting from document printer ${this.documentPrinter.name} before reconnecting...`,
|
||||||
@ -207,25 +257,17 @@ export class DocumentPrinterClient {
|
|||||||
const connectResult = await this.connect();
|
const connectResult = await this.connect();
|
||||||
if (connectResult == false) {
|
if (connectResult == false) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Error reconnecting to document printer ${this.documentPrinter.name}:`,
|
`Error reconnecting to document printer ${this.documentPrinter.name}`,
|
||||||
connectResult.error,
|
|
||||||
);
|
);
|
||||||
if (this.shouldReconnect) {
|
this.scheduleReconnect();
|
||||||
// Attempt to reconnect after delay
|
|
||||||
setTimeout(() => this.reconnect(), 30000);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const initializeResult = await this.initialize();
|
const initializeResult = await this.initialize();
|
||||||
if (initializeResult == false) {
|
if (initializeResult == false) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Error initializing document printer ${this.documentPrinter.name}:`,
|
`Error initializing document printer ${this.documentPrinter.name}`,
|
||||||
initializeResult.error,
|
|
||||||
);
|
);
|
||||||
if (this.shouldReconnect) {
|
this.scheduleReconnect();
|
||||||
// Attempt to reconnect after delay
|
|
||||||
setTimeout(() => this.reconnect(), 30000);
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,17 +323,33 @@ export class DocumentPrinterClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async updateDocumentPrinterState() {
|
async updateDocumentPrinterState() {
|
||||||
|
const updateData = {
|
||||||
|
online: this.isOnline,
|
||||||
|
state: this.state,
|
||||||
|
connectedAt: this.connectedAt ?? null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentConnectedAt = this.documentPrinter?.connectedAt;
|
||||||
|
const connectedAtUnchanged =
|
||||||
|
(currentConnectedAt?.toString?.() ?? null) ===
|
||||||
|
(updateData.connectedAt?.toString?.() ?? null);
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.documentPrinter?.online === updateData.online &&
|
||||||
|
this.statesEqual(this.documentPrinter?.state, updateData.state) &&
|
||||||
|
connectedAtUnchanged
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.documentPrinter = { ...this.documentPrinter, ...updateData };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Update state in database or via socket client
|
await this.socketClient.editObject({
|
||||||
// This can be implemented based on your database structure
|
|
||||||
this.socketClient.editObject({
|
|
||||||
_id: this.id,
|
_id: this.id,
|
||||||
objectType: "documentPrinter",
|
objectType: "documentPrinter",
|
||||||
updateData: {
|
updateData,
|
||||||
online: this.isOnline,
|
auditLog: true,
|
||||||
state: this.state,
|
|
||||||
connectedAt: this.connectedAt,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Failed to update document printer state:`, error);
|
logger.error(`Failed to update document printer state:`, error);
|
||||||
@ -308,8 +366,7 @@ export class DocumentPrinterClient {
|
|||||||
|
|
||||||
async updateJobState(jobId, state) {
|
async updateJobState(jobId, state) {
|
||||||
logger.info(`Updating job state for ${jobId}`);
|
logger.info(`Updating job state for ${jobId}`);
|
||||||
const notify =
|
const notify = state?.type !== "deploying" && state?.type !== "queued";
|
||||||
state?.type !== "deploying" && state?.type !== "queued";
|
|
||||||
await this.socketClient.editObject({
|
await this.socketClient.editObject({
|
||||||
_id: jobId,
|
_id: jobId,
|
||||||
objectType: "documentJob",
|
objectType: "documentJob",
|
||||||
@ -571,6 +628,8 @@ export class DocumentPrinterClient {
|
|||||||
async disconnect() {
|
async disconnect() {
|
||||||
logger.info(`Disconnecting from ${this.documentPrinter.name}`);
|
logger.info(`Disconnecting from ${this.documentPrinter.name}`);
|
||||||
this.shouldReconnect = false;
|
this.shouldReconnect = false;
|
||||||
|
clearTimeout(this.reconnectTimeout);
|
||||||
|
this.reconnectTimeout = null;
|
||||||
// Always stop the event update interval when disconnecting
|
// Always stop the event update interval when disconnecting
|
||||||
clearInterval(this.eventUpdateInterval);
|
clearInterval(this.eventUpdateInterval);
|
||||||
this.eventUpdateInterval = null;
|
this.eventUpdateInterval = null;
|
||||||
@ -583,7 +642,6 @@ export class DocumentPrinterClient {
|
|||||||
this.queue = []; // Clear queue on disconnect
|
this.queue = []; // Clear queue on disconnect
|
||||||
this.jobQuantities.clear();
|
this.jobQuantities.clear();
|
||||||
await this.updateDocumentPrinterState();
|
await this.updateDocumentPrinterState();
|
||||||
clearTimeout(this.reconnectTimeout);
|
|
||||||
logger.info(`Successfully disconnected from ${this.documentPrinter.name}`);
|
logger.info(`Successfully disconnected from ${this.documentPrinter.name}`);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -774,8 +774,6 @@ export class PrinterClient {
|
|||||||
);
|
);
|
||||||
this.filamentDetected = newFilamentDetected;
|
this.filamentDetected = newFilamentDetected;
|
||||||
|
|
||||||
console.log(this.currentFilamentStock);
|
|
||||||
|
|
||||||
if (newFilamentDetected == false && this.currentFilamentStock == null) {
|
if (newFilamentDetected == false && this.currentFilamentStock == null) {
|
||||||
await this.database.removeAlertsByCode("noFilamentLoaded");
|
await this.database.removeAlertsByCode("noFilamentLoaded");
|
||||||
await this.database.addAlert({
|
await this.database.addAlert({
|
||||||
@ -1175,9 +1173,12 @@ export class PrinterClient {
|
|||||||
|
|
||||||
const remainingTime = this.deploySubJobTargetTime - now;
|
const remainingTime = this.deploySubJobTargetTime - now;
|
||||||
clearTimeout(this.deploySubJobTimer);
|
clearTimeout(this.deploySubJobTimer);
|
||||||
this.deploySubJobTimer = setTimeout(() => {
|
this.deploySubJobTimer = setTimeout(
|
||||||
this.processDeploySubJobQueue();
|
() => {
|
||||||
}, Math.max(remainingTime, 0));
|
this.processDeploySubJobQueue();
|
||||||
|
},
|
||||||
|
Math.max(remainingTime, 0),
|
||||||
|
);
|
||||||
|
|
||||||
await this.database.updateSubJobState(subJob._id, {
|
await this.database.updateSubJobState(subJob._id, {
|
||||||
type: "deploying",
|
type: "deploying",
|
||||||
@ -1227,7 +1228,6 @@ export class PrinterClient {
|
|||||||
"with gcode file:",
|
"with gcode file:",
|
||||||
`${subJob.gcodeFile._id}`,
|
`${subJob.gcodeFile._id}`,
|
||||||
);
|
);
|
||||||
console.log("subJob", subJob);
|
|
||||||
const gcodeFile = await this.socketClient.getObject({
|
const gcodeFile = await this.socketClient.getObject({
|
||||||
objectType: "gcodeFile",
|
objectType: "gcodeFile",
|
||||||
_id: subJob.gcodeFile._id,
|
_id: subJob.gcodeFile._id,
|
||||||
@ -1237,8 +1237,6 @@ export class PrinterClient {
|
|||||||
throw new Error("G-code file not found");
|
throw new Error("G-code file not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("gcodeFile", gcodeFile);
|
|
||||||
|
|
||||||
const fileId = (gcodeFile.file?._id || gcodeFile.file).toString();
|
const fileId = (gcodeFile.file?._id || gcodeFile.file).toString();
|
||||||
let deploymentActive = true;
|
let deploymentActive = true;
|
||||||
|
|
||||||
@ -1517,9 +1515,7 @@ export class PrinterClient {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (speedFactor === undefined || speedFactor === null) {
|
if (speedFactor === undefined || speedFactor === null) {
|
||||||
logger.warn(
|
logger.warn(`No speed factor provided for ${this.printer.name}`);
|
||||||
`No speed factor provided for ${this.printer.name}`,
|
|
||||||
);
|
|
||||||
return this.printerActionResult(false, "No speed factor provided");
|
return this.printerActionResult(false, "No speed factor provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1550,7 +1546,10 @@ export class PrinterClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setExtrudeFactor({ extrudeFactor }) {
|
async setExtrudeFactor({ extrudeFactor }) {
|
||||||
logger.info(`Setting extrude factor for ${this.printer.name}:`, extrudeFactor);
|
logger.info(
|
||||||
|
`Setting extrude factor for ${this.printer.name}:`,
|
||||||
|
extrudeFactor,
|
||||||
|
);
|
||||||
|
|
||||||
if (!this.isOnline) {
|
if (!this.isOnline) {
|
||||||
logger.error(
|
logger.error(
|
||||||
@ -1564,9 +1563,7 @@ export class PrinterClient {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (extrudeFactor === undefined || extrudeFactor === null) {
|
if (extrudeFactor === undefined || extrudeFactor === null) {
|
||||||
logger.warn(
|
logger.warn(`No extrude factor provided for ${this.printer.name}`);
|
||||||
`No extrude factor provided for ${this.printer.name}`,
|
|
||||||
);
|
|
||||||
return this.printerActionResult(false, "No extrude factor provided");
|
return this.printerActionResult(false, "No extrude factor provided");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1710,10 +1707,7 @@ export class PrinterClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (squareCornerVelocity === undefined || squareCornerVelocity === null) {
|
||||||
squareCornerVelocity === undefined ||
|
|
||||||
squareCornerVelocity === null
|
|
||||||
) {
|
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`No square corner velocity provided for ${this.printer.name}`,
|
`No square corner velocity provided for ${this.printer.name}`,
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user