refactor: move kitchen printer socket communication to an isolated thread to improve reliability and performance
This commit is contained in:
parent
9248f9b7c8
commit
b7b882fb41
@ -5,6 +5,29 @@ from odoo import models, fields, api, _
|
|||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def _isolated_printer_thread(ip, data):
|
||||||
|
"""
|
||||||
|
Completely isolated printer thread.
|
||||||
|
Does not touch Odoo environment to avoid GIL/Locking issues.
|
||||||
|
"""
|
||||||
|
s = None
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
# 2 seconds is enough for a local network printer.
|
||||||
|
# Reducing from 5s to avoid holding resources too long.
|
||||||
|
s.settimeout(2.0)
|
||||||
|
s.connect((ip, 9100))
|
||||||
|
s.sendall(data)
|
||||||
|
_logger.info("POS_PRINTER: Successfully printed to %s", ip)
|
||||||
|
except Exception as e:
|
||||||
|
_logger.error("POS_PRINTER: Background print failed for IP %s: %s", ip, e)
|
||||||
|
finally:
|
||||||
|
if s:
|
||||||
|
try:
|
||||||
|
s.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
class PosPrinter(models.Model):
|
class PosPrinter(models.Model):
|
||||||
_inherit = 'pos.printer'
|
_inherit = 'pos.printer'
|
||||||
|
|
||||||
@ -28,26 +51,14 @@ class PosPrinter(models.Model):
|
|||||||
@api.model
|
@api.model
|
||||||
def print_network_kitchen_receipt(self, printer_id, receipt_data):
|
def print_network_kitchen_receipt(self, printer_id, receipt_data):
|
||||||
"""
|
"""
|
||||||
Receives structural receipt_data from POS frontend and sends ESC/POS string to network printer.
|
Receives structural receipt_data and sends to background worker.
|
||||||
Optimized to use background threading to prevent blocking the POS transaction/RPC.
|
|
||||||
"""
|
"""
|
||||||
printer = self.browse(printer_id)
|
printer = self.browse(printer_id)
|
||||||
if not printer or not printer.network_printer_ip:
|
if not printer or not printer.network_printer_ip:
|
||||||
return {'successful': False, 'message': 'Printer IP not configured'}
|
return {'successful': False, 'message': 'Printer IP not configured'}
|
||||||
|
|
||||||
# Start printing in a background thread to avoid POS timeout
|
# Build the ESC/POS data in the main thread (fast)
|
||||||
# We don't need a new cursor here as we've already browsed the printer
|
|
||||||
# and we don't write to the database in the thread.
|
|
||||||
thread = threading.Thread(target=self._threaded_print, args=(printer.network_printer_ip, receipt_data))
|
|
||||||
thread.daemon = True # Ensure thread doesn't block server shutdown
|
|
||||||
thread.start()
|
|
||||||
|
|
||||||
return {'successful': True, 'message': 'Print job sent to background queue'}
|
|
||||||
|
|
||||||
def _threaded_print(self, ip, receipt_data):
|
|
||||||
"""Perform the actual socket communication in the background."""
|
|
||||||
try:
|
try:
|
||||||
# Build basic ESC/POS commands
|
|
||||||
ESC = b'\x1b'
|
ESC = b'\x1b'
|
||||||
GS = b'\x1d'
|
GS = b'\x1d'
|
||||||
INIT = ESC + b'@'
|
INIT = ESC + b'@'
|
||||||
@ -92,12 +103,12 @@ class PosPrinter(models.Model):
|
|||||||
|
|
||||||
data += b"-" * 32 + NEWLINE + NEWLINE + NEWLINE + CUT
|
data += b"-" * 32 + NEWLINE + NEWLINE + NEWLINE + CUT
|
||||||
|
|
||||||
# Send to printer
|
# Start thread
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
t = threading.Thread(target=_isolated_printer_thread, args=(printer.network_printer_ip, data))
|
||||||
s.settimeout(5.0) # Slightly longer timeout for background print
|
t.daemon = True
|
||||||
s.connect((ip, 9100))
|
t.start()
|
||||||
s.sendall(data)
|
|
||||||
s.close()
|
return {'successful': True, 'message': 'Print job sent to background queue'}
|
||||||
_logger.info("Successfully printed to kitchen printer at %s", ip)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
_logger.error("Background kitchen print failed for IP %s: %s", ip, e)
|
_logger.error("POS_PRINTER: Failed to build print data: %s", e)
|
||||||
|
return {'successful': False, 'message': str(e)}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user