From 41139d3df588d23d95ed0d2ac53ea201252c4244 Mon Sep 17 00:00:00 2001 From: Dwi Swandhana Date: Fri, 30 Jan 2026 19:50:40 +0700 Subject: [PATCH] update --- htdocs/app/Services/AstmMessageService.php | 13 ++- listener/app.py | 119 +++++++++++++++------ 2 files changed, 97 insertions(+), 35 deletions(-) diff --git a/htdocs/app/Services/AstmMessageService.php b/htdocs/app/Services/AstmMessageService.php index 73433202..c05b48f5 100644 --- a/htdocs/app/Services/AstmMessageService.php +++ b/htdocs/app/Services/AstmMessageService.php @@ -840,7 +840,7 @@ class AstmMessageService try { // Ambil pesan ASTM dari kolom 'message' atau yang relevan $response = $data->rawdt; - if ($data->no_id != ''){ + if ($data->alat == 'MGIT' OR $data->alat == 'COM5' OR $data->alat == 'BACTEC'){ $assembled = $this->reassembleAstmFrames($data->rawdt); $messages = $this->splitBDAstmMessages($assembled); foreach ($messages as $msg) { @@ -864,9 +864,14 @@ class AstmMessageService ] ); } else { - DB::table('lis_phoenix')->where('id', $data->id)->update([ - 'processed' => 9 - ]); + $result = $this->processAstmResponse($data->rawdt, $data->alat); + if ($result) { + DataListiner::where('urut', $data->urut)->update([ + 'processed' => 1 + ]); + } else { + Log::debug($result); + } } } catch (\Exception $e) { Log::critical($e->getMessage()); diff --git a/listener/app.py b/listener/app.py index d570d33d..17bf1339 100644 --- a/listener/app.py +++ b/listener/app.py @@ -48,7 +48,9 @@ GENEXPERT_TEST_MAPPING = { "HCV VL": "HCV", # Xpert HCV Viral Load Version 1 # Mapping untuk IP 10.10.120.74 (Khusus) - "HBV VL": "HBV", # Xpert HBV Viral Load Version 1 + # Catatan: Di dokumen Anda tertulis Assay 'HBV' tapi kodenya 'HCV'. + # Pastikan ini benar, atau sesuaikan jika itu typo di dokumen. + "HBV VL": "HCV", } # Default code jika nama tes di database tidak dikenali @@ -72,16 +74,16 @@ app = Flask(__name__) active_genexpert_connections = {} connection_lock = threading.Lock() DEVICE_CONFIGS = [ - #{ - # 'port': 'COM6', 'baud_rate': 19200, 'device_type': 'vitek', 'alat_name': 'Vitek 1', - # 'protocol': 'serial', 'flag_column': 'flg_vitek1' - #}, + { + 'port': 'COM6', 'baud_rate': 19200, 'device_type': 'vitek', 'alat_name': 'Vitek 1', + 'protocol': 'serial', 'flag_column': 'flg_vitek1' + }, { 'port': 'COM4', 'baud_rate': 9600, 'device_type': 'vitek', 'alat_name': 'Vitek 2', 'protocol': 'serial', 'flag_column': 'flg_vitek2' }, { - 'port': 'COM3', 'baud_rate': 19200, 'device_type': 'bd', 'alat_name': 'BACTEC', + 'port': 'COM5', 'baud_rate': 19200, 'device_type': 'bd', 'alat_name': 'BACTEC', 'protocol': 'serial', 'flag_column': 'flg_bd1' }, #BD_MGIT yang di dalam ruangan isolasi @@ -292,11 +294,12 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"): # 4. Validasi Data Penting if not sample_id: + logging.warning("[HL7 Parser] Sample ID tidak ditemukan. Data tidak disimpan.") print("[HL7 Parser] Sample ID tidak ditemukan. Data tidak disimpan.") return + logging.info(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id} - {patient_name}") print(f"[HL7 Parser] Menyimpan hasil untuk Sample: {sample_id} - {patient_name}") - # 5. Simpan ke Database (Tabel LisPhoenix) new_data = LisPhoenix( no_id=sample_id, # OBR-3 @@ -310,9 +313,11 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"): session.add(new_data) session.commit() + logging.info(f"[DB] Berhasil simpan ke LisPhoenix: {sample_id}") print(f"[DB] Berhasil simpan ke LisPhoenix: {sample_id}") except Exception as e: + logging.error(f"[HL7 Parser] Error menyimpan data: {e}") print(f"[HL7 Parser] Error menyimpan data: {e}") session.rollback() finally: @@ -329,6 +334,7 @@ def parse_hl7_result(hl7_message, device_name="GeneXpert"): # ========================================== def handle_tcp_client(client_socket, addr): """Menangani satu koneksi client GeneXpert""" + logging.info(f"[TCP] Koneksi diterima dari {addr}") print(f"[TCP] Koneksi diterima dari {addr}") try: # Loop baca data dari client ini @@ -341,19 +347,22 @@ def handle_tcp_client(client_socket, addr): # decode, parsing ASTM, save to DB try: msg = data.decode('latin-1', errors='ignore') - print(f"[TCP] Data dari {addr}: {msg[:50]}...") + logging.info(f"[TCP] Data dari {addr}: {msg[:50]}...") + print(f"[TCP] Data dari {addr}: {msg[:50]}...") # Panggil fungsi parser GeneXpert Anda disini - # parse_and_save_genexpert(msg) + parse_hl7_result(msg, device_name=addr[0] if addr else "Unknown") # Kirim ACK ASTM jika perlu (\x06) client_socket.send(b'\x06') except Exception as e: + logging.error(f"[TCP] Error processing data: {e}") print(f"[TCP] Error processing data: {e}") - except Exception as e: + logging.error(f"[TCP] Koneksi Error {addr}: {e}") print(f"[TCP] Koneksi Error {addr}: {e}") finally: client_socket.close() + logging.info(f"[TCP] Koneksi ditutup {addr}") print(f"[TCP] Koneksi ditutup {addr}") def manage_tcp_server(): @@ -365,8 +374,8 @@ def manage_tcp_server(): try: server.bind((SERVER_HOST, TCP_LISTENER_PORT)) server.listen(5) # Bisa antri 5 koneksi + logging.info(f"[TCP-SERVER] Listening GeneXpert di port {TCP_LISTENER_PORT}...") print(f"[TCP-SERVER] Listening GeneXpert di port {TCP_LISTENER_PORT}...") - while True: # Accept koneksi baru (Blocking, tapi aman karena di thread sendiri) client_sock, addr = server.accept() @@ -380,6 +389,7 @@ def manage_tcp_server(): client_thread.start() except Exception as e: + logging.critical(f"[TCP-SERVER] Gagal Start: {e}") print(f"[TCP-SERVER] Gagal Start: {e}") def run_flask(): @@ -397,7 +407,7 @@ def send_mllp_message(sock, hl7_msg): def handle_genexpert_client(conn, addr): ip_sender = addr[0] logging.info(f"[CONNECT] GeneXpert terkoneksi dari IP: {ip_sender}") - + print(f"[CONNECT] GeneXpert terkoneksi dari IP: {ip_sender}") with connection_lock: active_genexpert_connections[ip_sender] = conn @@ -422,12 +432,13 @@ def handle_genexpert_client(conn, addr): hl7_str = raw_msg.decode('utf-8') logging.info(f"[RECV] Dari {ip_sender}: {hl7_str[:50]}...") # Log 50 karakter awal - + print(f"[RECV] Dari {ip_sender}: {hl7_str[:50]}...") # Print 50 karakter awal # Cek Tipe Pesan (MSH field 9) if "ORU^R01" in hl7_str: # Ini adalah Hasil - hasil = parse_hl7_result(hl7_str) + hasil = parse_hl7_result(hl7_str, device_name=addr[0] if addr else "GeneXpert") logging.info(f"[RESULT] {hasil}") + print(f"[RESULT] {hasil}") # TODO: Simpan 'hasil' ke database berdasarkan Sample ID di HL7 # Kirim ACK (Terima Kasih) ke Alat @@ -459,7 +470,7 @@ def run_tcp_server(): server.bind((SERVER_HOST, TCP_LISTENER_PORT)) server.listen(5) # Backlog 5 koneksi logging.info(f"TCP Listener AKTIF di port {TCP_LISTENER_PORT}. Menunggu koneksi GeneXpert...") - + print(f"TCP Listener AKTIF di port {TCP_LISTENER_PORT}. Menunggu koneksi GeneXpert...") while True: conn, addr = server.accept() # Buat thread baru untuk setiap alat yg konek @@ -468,6 +479,7 @@ def run_tcp_server(): except Exception as e: logging.critical(f"Gagal menjalankan TCP Server: {e}") + print(f"Gagal menjalankan TCP Server: {e}") def send_order_via_active_connection(target_ip, hl7_message): conn = None @@ -476,6 +488,7 @@ def send_order_via_active_connection(target_ip, hl7_message): if not conn: logging.warning(f"Gagal kirim Order: GeneXpert dengan IP {target_ip} BELUM TERKONEKSI ke Python.") + print(f"Gagal kirim Order: GeneXpert dengan IP {target_ip} BELUM TERKONEKSI ke Python.") return False # Indikasi gagal try: @@ -494,6 +507,7 @@ def send_order_via_active_connection(target_ip, hl7_message): return True except Exception as e: logging.error(f"Error mengirim ke {target_ip}: {e}") + print(f"Error mengirim ke {target_ip}: {e}") # Jika error saat kirim, anggap koneksi rusak with connection_lock: if target_ip in active_genexpert_connections: @@ -507,19 +521,22 @@ def broadcast_order_to_all_machines(hl7_message, order_id): if not connected_ips: logging.warning(f"Order {order_id} GAGAL dikirim: Tidak ada GeneXpert yang terkoneksi saat ini.") + print(f"Order {order_id} GAGAL dikirim: Tidak ada GeneXpert yang terkoneksi saat ini.") return False success_count = 0 logging.info(f"Memulai broadcast Order {order_id} ke {len(connected_ips)} alat...") - + print(f"Memulai broadcast Order {order_id} ke {len(connected_ips)} alat...") for target_ip in connected_ips: # Panggil fungsi kirim tunggal yang sudah kita buat sebelumnya # Note: Fungsi send_order_via_active_connection ada di kode sebelumnya if send_order_via_active_connection(target_ip, hl7_message): logging.info(f" -> Sukses kirim ke {target_ip}") + print(f" -> Sukses kirim ke {target_ip}") success_count += 1 else: logging.error(f" -> Gagal kirim ke {target_ip}") + print(f" -> Gagal kirim ke {target_ip}") # Logika bisnis: Dianggap sukses jika minimal terkirim ke SATU alat if success_count > 0: @@ -626,7 +643,7 @@ def parse_and_save_vitek_result(raw_data, port_name="VITEK"): final_res_string = "NEGATIVE / NO GROWTH" logging.info(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Bakteri: {organism_name}") - + print(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Bakteri: {organism_name}") new_entry = LisPhoenix( no_id=sample_id, # Menggunakan tag 'ci' seq_no=patient_id, # Menggunakan tag 'pi' @@ -641,11 +658,14 @@ def parse_and_save_vitek_result(raw_data, port_name="VITEK"): else: if msg_type != 'mtrsl': logging.info(f"[{port_name}] Mengabaikan pesan tipe {msg_type}") + print(f"[{port_name}] Mengabaikan pesan tipe {msg_type}") else: logging.warning(f"[{port_name}] Data tidak lengkap (No Sample ID). Raw: {raw_data[:50]}...") + print(f"[{port_name}] Data tidak lengkap (No Sample ID). Raw: {raw_data[:50]}...") except Exception as e: logging.error(f"Error Parsing Vitek: {e}") + print(f"Error Parsing Vitek: {e}") session.rollback() finally: session.close() @@ -704,7 +724,7 @@ def manage_vitek_port(config): flag_col = config.get('flag_column') alat_name = config.get('alat_name', 'VITEK') logging.info(f"[{port_name}] Membuka port untuk alat {alat_name}...") - + print(f"[{port_name}] Membuka port untuk alat {alat_name}...") # Buffer untuk menampung pecahan data rx_buffer = b"" @@ -730,6 +750,7 @@ def manage_vitek_port(config): # 1. Handle Handshake Awal (ENQ) - Alat minta izin kirim if b'\x05' in data_chunk: logging.info(f"[{port_name}] Terima ENQ. Kirim ACK.") + print(f"[{port_name}] Terima ENQ. Kirim ACK.") ser.write(b'\x06') # ACK rx_buffer = b"" # Reset buffer bytes continue @@ -754,12 +775,13 @@ def manage_vitek_port(config): parse_and_save_vitek_result(full_str, alat_name) except Exception as e: logging.error(f"[{port_name}] Error Decoding/Parsing: {e}") - + print(f"[{port_name}] Error Decoding/Parsing: {e}") rx_buffer = b"" # Bersihkan buffer continue except Exception as e: logging.error(f"[{port_name}] Error Reading: {e}") + print(f"[{port_name}] Error Reading: {e}") rx_buffer = b"" # Reset jika error parah @@ -778,7 +800,7 @@ def manage_vitek_port(config): if pending_order: has_activity = True # Jangan sleep lama-lama logging.info(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...") - + print(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...") # --- STEP 1: HANDSHAKE (ENQ) --- ser.reset_input_buffer() ser.write(b'\x05') @@ -789,6 +811,7 @@ def manage_vitek_port(config): if ack_response == b'\x06': logging.info(f"[{port_name}] Handshake dengan {alat_name}Sukses. Kirim Data...") + print(f"[{port_name}] Handshake dengan {alat_name} Sukses. Kirim Data...") time.sleep(1.0) # Jeda aman frames = create_vitek_order_message(pending_order) @@ -799,7 +822,8 @@ def manage_vitek_port(config): retry = 0 frame_sent = False while retry < 3: - logging.info(f"[{port_name}] Kirim Frame (Try {retry+1}): {frame}") # Log apa yang dikirim + logging.info(f"[{port_name}] Kirim Frame (Try {retry+1}): {frame}") + print(f"[{port_name}] Kirim Frame (Try {retry+1}): {frame}") ser.write(frame) # Tunggu ACK @@ -813,17 +837,21 @@ def manage_vitek_port(config): if response == b'\x06': # ACK logging.info(f"[{port_name}] Frame ACK (OK).") + print(f"[{port_name}] Frame ACK (OK).") frame_sent = True break elif response == b'\x15': # NAK logging.warning(f"[{port_name}] Dibalas NAK (Checksum/Format Salah).") + print(f"[{port_name}] Dibalas NAK (Checksum/Format Salah).") time.sleep(1) retry += 1 elif response is None: # TIMEOUT logging.warning(f"[{port_name}] Timeout (Alat tidak membalas). Cek Framing/Kabel.") + print(f"[{port_name}] Timeout (Alat tidak membalas). Cek Framing/Kabel.") retry += 1 else: # Respon Aneh logging.warning(f"[{port_name}] Respon aneh: {response}") + print(f"[{port_name}] Respon aneh: {response}") retry += 1 if not frame_sent: @@ -835,20 +863,23 @@ def manage_vitek_port(config): if all_success: logging.info(f"[{port_name}] Order {pending_order.rnoreg} SELESAI.") + print(f"[{port_name}] Order {pending_order.rnoreg} SELESAI.") setattr(pending_order, flag_col, True) session.commit() else: logging.error(f"[{port_name}] Gagal kirim order {pending_order.rnoreg}.") - + print(f"[{port_name}] Gagal kirim order {pending_order.rnoreg}.") else: # Handshake gagal (Alat sibuk/Mati) # logging.debug(f"[{port_name}] Alat sibuk/tidak balas ENQ.") + print(f"[{port_name}] Alat sibuk/tidak balas ENQ.") pass session.close() except Exception as e: logging.error(f"[{port_name}] Error Sending Logic: {e}") + print(f"[{port_name}] Error Sending Logic: {e}") if 'session' in locals(): session.close() # ========================================== @@ -861,6 +892,7 @@ def manage_vitek_port(config): except Exception as e: logging.critical(f"[{port_name}] Gagal connect Serial: {e}") + print(f"[{port_name}] Gagal connect Serial: {e}") time.sleep(5) # ========================================== @@ -946,7 +978,7 @@ def parse_and_save_bd_result(raw_data, port_name="BD Bactec"): final_res_string += f" ({specimen_type})" logging.info(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Hasil: {final_res_string}") - + print(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Hasil: {final_res_string}") new_entry = LisPhoenix( no_id=sample_id, seq_no=patient_id, @@ -960,9 +992,11 @@ def parse_and_save_bd_result(raw_data, port_name="BD Bactec"): session.commit() else: logging.warning(f"[{port_name}] Data tidak lengkap. ID: {sample_id}, Res: {result_val}") + print(f"[{port_name}] Data tidak lengkap. ID: {sample_id}, Res: {result_val}") except Exception as e: logging.error(f"Error Parsing BD: {e}") + print(f"Error Parsing BD: {e}") session.rollback() finally: session.close() @@ -1092,6 +1126,7 @@ def manage_bd_port(config): # 1. Handle Handshake Awal (ENQ) if b'\x05' in data_chunk: logging.info(f"[{port_name}] Terima ENQ (Alat mau kirim data). Kirim ACK.") + print(f"[{port_name}] Terima ENQ (Alat mau kirim data). Kirim ACK.") ser.write(b'\x06') # ACK rx_buffer = "" # Reset buffer untuk data baru continue @@ -1099,6 +1134,7 @@ def manage_bd_port(config): # 2. Handle Akhir Transmisi (EOT) if b'\x04' in data_chunk: logging.info(f"[{port_name}] Terima EOT (Selesai). Memproses data...") + print(f"[{port_name}] Terima EOT (Selesai). Memproses data...") # Proses semua data yang terkumpul di buffer parse_and_save_bd_result(rx_buffer, alat_name) rx_buffer = "" # Kosongkan buffer setelah save @@ -1118,11 +1154,13 @@ def manage_bd_port(config): # logging.debug(f"[{port_name}] Frame diterima, ACK dikirim.") except Exception as e: logging.error(f"Error decode frame: {e}") + print(f"Error decode frame: {e}") continue # Loop lagi untuk ambil sisa data except Exception as e: logging.error(f"[{port_name}] Error Reading: {e}") + print(f"[{port_name}] Error Reading: {e}") rx_buffer = b"" # Reset jika error parah @@ -1141,7 +1179,7 @@ def manage_bd_port(config): if pending_order: has_activity = True # Jangan sleep lama-lama logging.info(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...") - + print(f"[{port_name}] Menemukan Order: {pending_order.rnoreg}. Memulai Handshake...") # --- STEP 1: HANDSHAKE (ENQ) --- ser.reset_input_buffer() ser.write(b'\x05') @@ -1151,7 +1189,7 @@ def manage_bd_port(config): if ack_response == b'\x06': logging.info(f"[{port_name}] Handshake Sukses (Dapat ACK). Menunggu alat siap...") - + print(f"[{port_name}] Handshake Sukses (Dapat ACK). Menunggu alat siap...") # --- PERBAIKAN 1: BERI JEDA SETELAH HANDSHAKE --- # Mesin butuh napas sebelum terima data panjang time.sleep(1.5) # Jeda 1.5 detik @@ -1171,6 +1209,7 @@ def manage_bd_port(config): ser.reset_input_buffer() logging.info(f"[{port_name}] Kirim Frame {i+1} (Percobaan {retry_count+1})...") + print(f"[{port_name}] Kirim Frame {i+1} (Percobaan {retry_count+1})...") ser.write(frame) # Tunggu ACK @@ -1182,28 +1221,33 @@ def manage_bd_port(config): if frame_ack == b'\x06': # ACK (Sukses) frame_success = True logging.info(f"[{port_name}] Frame {i+1} ACK diterima.") + print(f"[{port_name}] Frame {i+1} ACK diterima.") # Beri jeda dikit sebelum kirim frame berikutnya time.sleep(0.2) break elif frame_ack == b'\x15': # NAK (Ditolak - Checksum Salah) logging.warning(f"[{port_name}] Frame ditolak (NAK). Checksum mungkin salah.") + print(f"[{port_name}] Frame ditolak (NAK). Checksum mungkin salah.") time.sleep(2) # Tunggu 2 detik retry_count += 1 elif not frame_ack: # Timeout (Sepi) # --- PERBAIKAN 2: BERI JEDA SAAT TIMEOUT --- logging.warning(f"[{port_name}] Timeout (Alat diam). Menunggu sebelum retry...") + print(f"[{port_name}] Timeout (Alat diam). Menunggu sebelum retry...") time.sleep(2) # Tunggu 2 detik agar alat recover retry_count += 1 else: logging.warning(f"[{port_name}] Respon aneh: {frame_ack}") + print(f"[{port_name}] Respon aneh: {frame_ack}") time.sleep(1) retry_count += 1 if not frame_success: logging.error(f"[{port_name}] Gagal kirim frame ke-{i+1}. Batal.") + print(f"[{port_name}] Gagal kirim frame ke-{i+1}. Batal.") all_frames_sent = False break # --------------------------------------------------- @@ -1212,17 +1256,18 @@ def manage_bd_port(config): if all_frames_sent: ser.write(b'\x04') # EOT (End of Transmission) logging.info(f"[{port_name}] Order {pending_order.rnoreg} SUKSES Terkirim.") - + print(f"[{port_name}] Order {pending_order.rnoreg} SUKSES Terkirim.") # Update Database setattr(pending_order, flag_col, True) session.commit() else: ser.write(b'\x04') # EOT (Putus paksa karena error) logging.error(f"[{port_name}] Pengiriman Order GAGAL.") - + print(f"[{port_name}] Pengiriman Order GAGAL.") else: # Jika Handshake gagal (Dibalas NAK, atau Timeout) logging.warning(f"[{port_name}] Handshake Gagal. Respon alat: {ack_response}") + print(f"[{port_name}] Handshake Gagal. Respon alat: {ack_response}") # Jangan update flag DB, biarkan coba lagi nanti @@ -1230,6 +1275,7 @@ def manage_bd_port(config): except Exception as e: logging.error(f"[{port_name}] Error Sending Logic: {e}") + print(f"[{port_name}] Error Sending Logic: {e}") if 'session' in locals(): session.close() # ========================================== @@ -1242,6 +1288,7 @@ def manage_bd_port(config): except Exception as e: logging.critical(f"[{port_name}] Gagal connect Serial: {e}") + print(f"[{port_name}] Gagal connect Serial: {e}") time.sleep(5) # ========================================== @@ -1251,7 +1298,7 @@ def manage_bd_port(config): def order_poller(stop_event): """Looping cek DB dan kirim order ke SEMUA alat""" logging.info("Order Poller Berjalan...") - + print("Order Poller Berjalan...") while not stop_event.is_set(): session = SessionLocal() try: @@ -1286,8 +1333,10 @@ def order_poller(stop_event): send_mllp_message(conn, hl7_msg) order.flg_gxp1 = True # Update Flag logging.info(f"[SENT] Order {order.rnoreg} dikirim ke GXP-1 ({target_ip})") + print(f"[SENT] Order {order.rnoreg} dikirim ke GXP-1 ({target_ip})") except Exception as e: logging.error(f"[FAIL] Gagal kirim ke GXP-1: {e}") + print(f"[FAIL] Gagal kirim ke GXP-1: {e}") else: # Alat 1 belum connect, biarkan False (pending) pass @@ -1301,8 +1350,10 @@ def order_poller(stop_event): send_mllp_message(conn, hl7_msg) order.flg_gxp2 = True logging.info(f"[SENT] Order {order.rnoreg} dikirim ke GXP-2 ({target_ip})") + print(f"[SENT] Order {order.rnoreg} dikirim ke GXP-2 ({target_ip})") except Exception as e: logging.error(f"[FAIL] Gagal kirim ke GXP-2: {e}") + print(f"[FAIL] Gagal kirim ke GXP-2: {e}") # 3. Cek Target GXP 3 if order.flg_gxp3 == False: @@ -1313,13 +1364,16 @@ def order_poller(stop_event): send_mllp_message(conn, hl7_msg) order.flg_gxp3 = True logging.info(f"[SENT] Order {order.rnoreg} dikirim ke GXP-3 ({target_ip})") + print(f"[SENT] Order {order.rnoreg} dikirim ke GXP-3 ({target_ip})") except Exception as e: logging.error(f"[FAIL] Gagal kirim ke GXP-3: {e}") + print(f"[FAIL] Gagal kirim ke GXP-3: {e}") # Commit perubahan flag ke database session.commit() except Exception as e: logging.error(f"Error Poller: {e}") + print(f"Error Poller: {e}") session.rollback() finally: session.close() @@ -1335,7 +1389,7 @@ def manage_serial_port(config): manage_bd_port(config) else: logging.error(f"Tipe alat tidak diketahui: '{device_type}' untuk port {config.get('port')}. Thread dihentikan.") - + print(f"Tipe alat tidak diketahui: '{device_type}' untuk port {config.get('port')}. Thread dihentikan.") # ========================================== # 6. FLASK API (Opsional) # ========================================== @@ -1388,25 +1442,28 @@ if __name__ == "__main__": # Ini sekarang bisa berjalan karena Flask sudah dipindah ke thread try: while True: + logging.debug(f"--- Monitoring {len(all_threads)} Threads ---") print(f"--- Monitoring {len(all_threads)} Threads ---") - # Cek status setiap thread alive_count = 0 for t in all_threads: if t.is_alive(): alive_count += 1 else: + logging.warning(f"!!! THREAD MATI: {t.name} !!!") print(f"!!! THREAD MATI: {t.name} !!!") # Disini Anda bisa menambahkan logika restart thread jika mati # Jika semua mati, exit (atau restart service) if alive_count == 0: logging.critical("Semua thread mati. System Shutdown.") + print("Semua thread mati. System Shutdown.") break time.sleep(10) # Cek setiap 10 detik (Hemat CPU) except KeyboardInterrupt: + logging.info("Mematikan Service (Ctrl+C)...") print("Mematikan Service (Ctrl+C)...") stop_event.set() - # Thread daemon akan mati otomatis saat main exit \ No newline at end of file + # Thread daemon akan mati otomatis saat main exit