jetstream-api 0.11.0__tar.gz → 0.12.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/PKG-INFO +13 -1
  2. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/README.md +12 -0
  3. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/__init__.py +1 -1
  4. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/common.py +7 -0
  5. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/connectivity.py +41 -1
  6. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/qmgr.py +94 -6
  7. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/jetstream_api.egg-info/PKG-INFO +13 -1
  8. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/pyproject.toml +1 -1
  9. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/LICENSE.txt +0 -0
  10. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/_codec.py +0 -0
  11. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/admin.py +0 -0
  12. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/admintopic.py +0 -0
  13. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/exception.py +0 -0
  14. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/msg.py +0 -0
  15. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/partitioner.py +0 -0
  16. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/pattern.py +0 -0
  17. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/producer.py +0 -0
  18. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/properties.py +0 -0
  19. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/py.typed +0 -0
  20. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/topic.py +0 -0
  21. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/ilink/util.py +0 -0
  22. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/jetstream_api.egg-info/SOURCES.txt +0 -0
  23. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/jetstream_api.egg-info/dependency_links.txt +0 -0
  24. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/jetstream_api.egg-info/requires.txt +0 -0
  25. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/jetstream_api.egg-info/top_level.txt +0 -0
  26. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/setup.cfg +0 -0
  27. {jetstream_api-0.11.0 → jetstream_api-0.12.0}/tests/test_example.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jetstream-api
3
- Version: 0.11.0
3
+ Version: 0.12.0
4
4
  Summary: Python client API for iLink M.O.M. (Message Oriented Middleware)
5
5
  Author: snowjeans
6
6
  License: Boost Software License - Version 1.0 - August 17th, 2003
@@ -60,6 +60,18 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
60
60
  ## 설치 방법
61
61
  pip install jetstream-api
62
62
 
63
+ ## 0.12.0 변경 - 큐 전용 요청 코드(엔진 7.0.1.3431 이상) 자동 사용 (자바 v2.8.0 과 같음)
64
+
65
+ - **앱 코드는 바꿀 것이 없습니다.** 엔진 판 줄이 7.x 이고 리비전이 3431 이상이면 클라이언트가 스스로 새 요청 코드를 씁니다.
66
+ 그 밖의 엔진(6.3.x, 그보다 앞선 7.x, 5.x)에는 0.11.0 과 같은 요청을 보냅니다.
67
+ - **`commit_and_get`** 은 커밋 요청과 get 요청 대신 전용 요청 하나(COMMIT_AND_GET, 3402)를 보내고 응답도 하나만 받습니다.
68
+ 엔진이 커밋한 뒤 곧바로 get 을 돌립니다. 결과와 예외는 0.11.0 과 같습니다.
69
+ - 커밋이 거절되면 get 은 돌지 않았고, 롤백을 보내 커밋하려던 작업과 꺼낸 메시지를 큐에 되돌린 뒤 `ILOperationException` 을 올립니다.
70
+ - 응답을 받기 전에 연결이 끊기면 커밋 결과를 알 수 없습니다(재접속 / 재시도 없음). 커밋 결과가 get 결과와 한 응답으로 오므로
71
+ **결과를 알 수 없는 구간이 get 대기 시간까지** 늘어납니다.
72
+ - **`commit()`** 은 쥐고 있던 트랜잭션 put 이 **하나뿐**이면 put 과 커밋 대신 전용 요청 하나(PUT_AND_COMMIT, 3403)로 보냅니다.
73
+ 돌려주는 값과 예외는 같습니다. put 이 둘 이상이거나 `puts`, 64KiB 를 넘는 put, 쥔 것이 없을 때는 0.11.0 과 같습니다.
74
+
63
75
  ## 0.11.0 변경 - 큐 단건 put / get 가속, `commit_and_get` 추가
64
76
 
65
77
  - **새 API `ILQueue.commit_and_get(matchId=None, option=MatchOption.NONE)`** (camelCase 별칭 `commitAndGet`): 이 세션의
@@ -10,6 +10,18 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
10
10
  ## 설치 방법
11
11
  pip install jetstream-api
12
12
 
13
+ ## 0.12.0 변경 - 큐 전용 요청 코드(엔진 7.0.1.3431 이상) 자동 사용 (자바 v2.8.0 과 같음)
14
+
15
+ - **앱 코드는 바꿀 것이 없습니다.** 엔진 판 줄이 7.x 이고 리비전이 3431 이상이면 클라이언트가 스스로 새 요청 코드를 씁니다.
16
+ 그 밖의 엔진(6.3.x, 그보다 앞선 7.x, 5.x)에는 0.11.0 과 같은 요청을 보냅니다.
17
+ - **`commit_and_get`** 은 커밋 요청과 get 요청 대신 전용 요청 하나(COMMIT_AND_GET, 3402)를 보내고 응답도 하나만 받습니다.
18
+ 엔진이 커밋한 뒤 곧바로 get 을 돌립니다. 결과와 예외는 0.11.0 과 같습니다.
19
+ - 커밋이 거절되면 get 은 돌지 않았고, 롤백을 보내 커밋하려던 작업과 꺼낸 메시지를 큐에 되돌린 뒤 `ILOperationException` 을 올립니다.
20
+ - 응답을 받기 전에 연결이 끊기면 커밋 결과를 알 수 없습니다(재접속 / 재시도 없음). 커밋 결과가 get 결과와 한 응답으로 오므로
21
+ **결과를 알 수 없는 구간이 get 대기 시간까지** 늘어납니다.
22
+ - **`commit()`** 은 쥐고 있던 트랜잭션 put 이 **하나뿐**이면 put 과 커밋 대신 전용 요청 하나(PUT_AND_COMMIT, 3403)로 보냅니다.
23
+ 돌려주는 값과 예외는 같습니다. put 이 둘 이상이거나 `puts`, 64KiB 를 넘는 put, 쥔 것이 없을 때는 0.11.0 과 같습니다.
24
+
13
25
  ## 0.11.0 변경 - 큐 단건 put / get 가속, `commit_and_get` 추가
14
26
 
15
27
  - **새 API `ILQueue.commit_and_get(matchId=None, option=MatchOption.NONE)`** (camelCase 별칭 `commitAndGet`): 이 세션의
@@ -1,6 +1,6 @@
1
1
  """iLink - Python client API for iLink M.O.M. (Message Oriented Middleware)."""
2
2
 
3
- __version__ = "0.11.0"
3
+ __version__ = "0.12.0"
4
4
 
5
5
  # --- Admin / Service ---
6
6
  from .admin import ILAdminService, ILAdminQmgr, ILLogBrowser, ILQueueBrowser
@@ -467,6 +467,13 @@ class ILC:
467
467
  #: SUBSCRIPTION_NOT_FOUND, 그 (토픽, 구독)에 read 가 걸려 있으면(태그 롱폴 / FETCH_MULTI 항목) 4157
468
468
  #: MIMQE_READ_IN_PROGRESS. 다시 read 하면 다시 든다(재배정 통지부터). r3416 이하 엔진은 모르는 요청으로 거절한다.
469
469
  MIMQ_TOPIC_LEAVE = 3401
470
+ #: 0.12.0(엔진 r3431, 사용자 결정 2026-09-15): 큐 전용 요청. 판 줄 major 가 7 이고 리비전이 3431 이상인 엔진에만 보낸다.
471
+ #: 칸은 GET 과 같다(arg2 큐 이름, arg3 대기 ms, 확장 = 선택자). 트랜잭션 세션이면 엔진이 커밋한 뒤 GET 을 돌려 GET 응답
472
+ #: 하나만 준다. 커밋이 실패하면 MIMQ_NOT_SUCCESSFUL_COMMIT 하나만 온다(GET 은 돌지 않았다).
473
+ MIMQ_COMMIT_AND_GET_REQUEST = 3402
474
+ #: 0.12.0(엔진 r3431): 인자 없음, 확장 = DATA 프레임 하나(put 이 보내는 프레임). 응답은 COMMIT 과 같다. commit() 이 쥔 것이
475
+ #: 트랜잭션 put 하나뿐일 때 [PUT + COMMIT] 대신 쓴다.
476
+ MIMQ_PUT_AND_COMMIT_REQUEST = 3403
470
477
 
471
478
  # 토픽 응답 코드
472
479
  MIMQ_SUCCESSFUL_TOPIC_OPERATION = 4156
@@ -506,6 +506,8 @@ class TCPConnector:
506
506
  # 0.11.0 K2: 응답이 없는 송신(트랜잭션 세션의 put)을 쥐고 있다가 이 연결의 다음 송신과 한 번에 쓴다(send_deferred)
507
507
  self._wpend: list = []
508
508
  self._wpend_len = 0
509
+ #: 0.12.0: 쥔 첫 프레임이 put(DATA)인가 - _single_pending_put 이 본다(쥔 것이 하나일 때만 뜻이 있다)
510
+ self._wpend_put1 = False
509
511
 
510
512
  def _rx_reset(self) -> None:
511
513
  # 받아 둔 바이트와 쥔 송신을 버린다(끊기 / 새 접속). 다음 수신은 timeout 을 다시 준다
@@ -676,11 +678,20 @@ class TCPConnector:
676
678
  data = msg.toByteArray(True)
677
679
  if (self.socket is not None and self._is_connected() and len(data) <= _WPEND_FRAME_MAX
678
680
  and self._wpend_len + len(data) <= _WPEND_TOTAL_MAX):
681
+ # 0.12.0: 쥔 것이 put 프레임 하나뿐인지 본다(commit 이 PUT_AND_COMMIT 로 바꿔 쓸지). 빈 자리에 처음 쥘 때 정한다
682
+ if not self._wpend:
683
+ self._wpend_put1 = msg.getType() == ILC.MIMQ_DATA_MESSAGE
679
684
  self._wpend.append(data)
680
685
  self._wpend_len += len(data)
681
686
  return
682
687
  self.send_bytes(data)
683
688
 
689
+ def _single_pending_put(self) -> bytes | None:
690
+ # 0.12.0: 쥔 것이 put(DATA) 프레임 하나뿐이면 그 프레임(전송 구분자 포함), 아니면 None. 쥔 것은 그대로 둔다(연결 잠금 안에서 부른다)
691
+ if len(self._wpend) == 1 and self._wpend_put1:
692
+ return self._wpend[0]
693
+ return None
694
+
684
695
  def _flush_wpend(self, sock) -> None:
685
696
  # 쥔 송신을 내보낸다(K2). 실패는 송신 실패와 같은 사유로 올린다 - 부르는 쪽이 연결을 닫는다
686
697
  data = b"".join(self._wpend)
@@ -692,7 +703,9 @@ class TCPConnector:
692
703
  raise ILSessionException(ILRC.MIMQE_BIO_ERROR, "write() failure.", exc) from exc
693
704
 
694
705
  def _discard_wpend(self) -> None:
695
- # rollback 이 부른다 - 쥔 put 은 아직 엔진에 가지 않았으므로 버리면 보낸 뒤 롤백한 것과 같다
706
+ # _request_const(discard_pending=True) 가 부른다 - 지금은 그렇게 부르는 곳이 없다(rollback 도 쥔 put 을 ROLLBACK 과 함께
707
+ # 보내 0.10.0 과 같은 롤백 응답을 받는다). 끊기 / 새 접속 때 비우는 것은 _rx_reset 이다
708
+ # 쥔 put 은 아직 엔진에 가지 않았으므로 버리면 보낸 뒤 롤백한 것과 같다
696
709
  self._wpend.clear()
697
710
  self._wpend_len = 0
698
711
 
@@ -1390,6 +1403,33 @@ class ILRequestHelper:
1390
1403
  report_msg._arrival = getattr(res_msg, "_arrival", 0)
1391
1404
  return report_msg
1392
1405
 
1406
+ def _request_put_and_commit(self) -> ILReportMsg | None:
1407
+ # 0.12.0: 연결이 쥔 것이 put(DATA) 프레임 하나뿐이면 [PUT + COMMIT] 대신 PUT_AND_COMMIT(3403) 하나로 보내고 응답(COMMIT 과
1408
+ # 같은 보고)을 돌려준다. 쥔 것이 없거나 둘 이상 / 태그 계층 / 라이브러리 커넥터가 아님 / 프레임 상한을 넘음 = None - 부르는
1409
+ # 쪽이 COMMIT 을 보낸다(쥔 것은 그 앞에 붙어 나간다). 엔진 판 확인(7.x 리비전 3431 이상)은 부르는 쪽(ILQmgr.commit)이 한다
1410
+ conn = self.conn
1411
+ if type(conn) is not TCPConnector or self._gate is not None:
1412
+ return None
1413
+ with _io_lock_of(conn):
1414
+ put = conn._single_pending_put()
1415
+ if put is None:
1416
+ return None
1417
+ # 확장 = 쥔 put 프레임에서 끝 전송 구분자를 뺀 것 = to_byte_array(False), PUTS 서브메시지와 같은 형식(엔진 확인 2026-09-15).
1418
+ # 엔진은 확장이 DATA 프레임 하나이고 그 길이 칸 값이 확장 바이트 수와 같은지 본다(구분자가 붙으면 거절 + 롤백)
1419
+ frame = ILMsgUtil.create_request_msg_with_ext(ILC.MIMQ_PUT_AND_COMMIT_REQUEST, bytes(put[:-1])).to_byte_array(True)
1420
+ if len(frame) - 1 > conn.max_frame_length:
1421
+ return None
1422
+ conn._discard_wpend()
1423
+ conn.send_bytes(frame)
1424
+ res_msg = _stamp_arrival(conn.recv(self.sessionTimeoutMS), self._arrivals)
1425
+ if ILC.MIMQ_REPORT_MESSAGE != res_msg.getType():
1426
+ raise ILMsgTypeException(
1427
+ res_msg.getType(), " msg type must be [MIMQ_REPORT_MESSAGE]"
1428
+ )
1429
+ report_msg = res_msg.getReportMsg()
1430
+ report_msg._arrival = getattr(res_msg, "_arrival", 0)
1431
+ return report_msg
1432
+
1393
1433
  @contextlib.contextmanager
1394
1434
  def _exclusive(self):
1395
1435
  # 연결을 다시 붙이는 동안 혼자 쓴다. 진행 중인 호출(걸린 롱폴 포함)이 끝나기를 기다리고 새 호출은 그 뒤에 세운다
@@ -88,6 +88,27 @@ def _engine_in_order(version: str) -> bool:
88
88
  return major == 6 and minor == 3 and m.group(3) is not None and int(m.group(3)) >= 3
89
89
 
90
90
 
91
+ # 0.12.0: 큐 전용 요청 코드(COMMIT_AND_GET 3402 / PUT_AND_COMMIT 3403)를 아는 엔진인가 - 판 줄 major 가 7 이고 리비전(넷째 칸)이
92
+ # 3431 이상(엔진 r3431, 사용자 결정 2026-09-15). 6.3.x / 옛 7.x / 판을 읽지 못함 = 0.11.0 경로(자바 v2.8.0 과 같다)
93
+ # 네 칸 모두 숫자이고 그 뒤는 공백이나 끝이어야 한다(자바 ILQueue.isQueueFastEngine 과 같은 판정)
94
+ _VERSION_FULL = re.compile(r"\s*([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)(?:\s|$)")
95
+ _QUEUE_FAST_REVISION = 3431
96
+
97
+
98
+ @functools.lru_cache(maxsize=16)
99
+ def _engine_qfast(version: str) -> bool:
100
+ """엔진 판 문자열이 큐 전용 요청 코드(3402 / 3403)를 아는 판인지.
101
+
102
+ Args:
103
+ version (str): :meth:`ILQmgr.get_version` 값(예 ``"7.0.1.3431 jetstream"``).
104
+
105
+ Returns:
106
+ bool: 판 줄 major 가 7 이고 리비전(넷째 칸)이 3431 이상이면 True.
107
+ """
108
+ m = _VERSION_FULL.match(version)
109
+ return m is not None and int(m.group(1)) == 7 and int(m.group(4)) >= _QUEUE_FAST_REVISION
110
+
111
+
91
112
  class ILQmgr:
92
113
  """큐 관리자에 붙어 메시지를 넣고 빼는 **응용 클라이언트**.
93
114
 
@@ -608,6 +629,9 @@ class ILQmgr:
608
629
  큐 하나가 아니라 **세션 전체**가 단위다. 여러 큐에 걸친 put/get 이
609
630
  한 트랜잭션으로 묶여 원자적으로 확정된다.
610
631
 
632
+ 엔진 7.x 리비전 3431 이상이고, 아직 보내지 않고 쥐고 있던 트랜잭션 put 이 **하나뿐**이면 put 과 커밋 대신
633
+ 전용 요청 하나(PUT_AND_COMMIT)로 보낸다(0.12.0). 뜻 · 반환값 · 예외는 같다(앞선 작업이 있으면 함께 확정된다).
634
+
611
635
  Example::
612
636
 
613
637
  qmgr.connect("192.168.0.10", 5000, auto_commit=False)
@@ -618,7 +642,15 @@ class ILQmgr:
618
642
  """
619
643
  try:
620
644
  self.txnPending = False
621
- report_msg = self._request_const(_COMMIT)
645
+ report_msg = None
646
+ # 0.12.0: 쥔 것이 트랜잭션 put 하나뿐이고 엔진이 PUT_AND_COMMIT 를 알면(7.x 리비전 3431 이상) [PUT + COMMIT] 대신 그
647
+ # 요청 하나로 보낸다. 뜻과 응답은 put() + commit() 과 같다(앞선 작업이 있으면 함께 커밋된다, 자바 v2.8.0 과 같다)
648
+ if _engine_qfast(self.get_version() or ""):
649
+ fast = getattr(self.service, "_request_put_and_commit", None)
650
+ if fast is not None:
651
+ report_msg = fast()
652
+ if report_msg is None:
653
+ report_msg = self._request_const(_COMMIT)
622
654
  if report_msg is None:
623
655
  raise ILOperationException("MIMQE_INTERNAL_ERROR")
624
656
  if report_msg.getCode() != ILC.MIMQ_SUCCESSFUL_COMMIT:
@@ -1627,6 +1659,8 @@ class ILQueue:
1627
1659
  self.isInfiniteWaiting = False
1628
1660
  # 0.11.0 K7: 마지막으로 짠 GET 요청 (대기 시간 문자열, 선택자, 큐 이름, ILMsg, 프레임 바이트)
1629
1661
  self._getCache = None
1662
+ # 0.12.0: 마지막으로 짠 COMMIT_AND_GET 프레임 (대기 시간 문자열, 선택자, 큐 이름, 프레임 바이트)
1663
+ self._cagCache = None
1630
1664
 
1631
1665
  if not existCheck:
1632
1666
  return
@@ -2041,17 +2075,19 @@ class ILQueue:
2041
2075
  ILNoMsgException: 대기 시간(:meth:`set_wait_msg_timeout_ms`, 기본 60초) 안에 메시지가 없을 때.
2042
2076
  **이때도 커밋은 이미 성공했다.**
2043
2077
  ILOperationException: 커밋이 실패했을 때(:meth:`ILQmgr.commit` 과 같은 예외, 사유는 엔진이 준 값). 이때는
2044
- 커밋 뒤에 보낸 get 이 꺼낸 메시지를 롤백으로 큐에 되돌린 뒤 올린다. 또는 커밋은 성공했는데 get 을
2078
+ 롤백을 보내 커밋하려던 작업과 꺼낸 메시지를 큐에 되돌린 뒤 올린다. 또는 커밋은 성공했는데 get 을
2045
2079
  엔진이 거절했을 때(:meth:`get` 과 같은 예외).
2046
- ILSessionException: 커밋 요청을 보낸 뒤 커밋 응답을 받기 전에 연결이 끊겼을 때. **커밋 결과를 알 수 없으므로
2080
+ ILSessionException: 커밋 요청을 보낸 뒤 커밋 결과를 받기 전에 연결이 끊겼을 때. **커밋 결과를 알 수 없으므로
2047
2081
  자동 재접속 / 재시도를 하지 않는다**(:meth:`ILQmgr.commit` 과 같다) - 다시 붙어 트랜잭션을 처음부터 수행한다.
2082
+ 전용 요청(아래 Note)이면 커밋 결과가 get 결과와 한 응답으로 오므로 이 구간이 **get 대기 시간까지** 늘어난다.
2048
2083
  ILException: 그 밖의 통신 실패.
2049
2084
 
2050
2085
  Note:
2051
2086
  * 자동 커밋 세션(``auto_commit=True``)이면 커밋 요청 없이 :meth:`get` 과 똑같이 동작한다.
2052
- * 연달아 보내기는 한 세션의 요청을 받은 순서대로 처리하고 그 순서로 답하는 것이 확인된 엔진(7.x, 6.3.3 이상의
2053
- 6.3.x)에서만 한다. 그 밖의 엔진(5.x 등, 판을 읽지 못한 경우 포함)에서는 커밋 응답을 받은 뒤 get 을 보낸다 -
2054
- 결과는 같고 2 왕복이다. 어느 쪽이든 와이어 형식은 그대로다.
2087
+ * 엔진 7.x 리비전 3431 이상에는 **전용 요청 하나(COMMIT_AND_GET)** 를 보내고 응답도 하나만 받는다(0.12.0 - 엔진이
2088
+ 커밋한 뒤 곧바로 get 을 돌린다). 한 세션의 요청을 받은 순서대로 처리하고 그 순서로 답하는 것이 확인된 그 밖의
2089
+ 엔진(그보다 앞선 7.x, 6.3.3 이상의 6.3.x)에는 커밋과 get 요청을 연달아 보낸다(와이어 형식은 0.10.0 과 같다). 그 밖의
2090
+ 엔진(5.x 등, 판을 읽지 못한 경우 포함)에서는 커밋 응답을 받은 뒤 get 을 보낸다 - 결과는 같고 2 왕복이다.
2055
2091
  * 커밋이 성공한 뒤 get 이 통신 장애로 실패하면 :meth:`get` 과 같이 자동 재접속 후 1회 재시도한다(커밋할 것이
2056
2092
  이제 없다).
2057
2093
  * 무한 대기(``set_wait_msg_timeout_ms(-1)``)면 첫 get 이 비었을 때 :meth:`get` 과 같이 계속 기다린다.
@@ -2088,12 +2124,64 @@ class ILQueue:
2088
2124
  # 순서 처리가 확인되지 않은 엔진 / 커밋과 큐가 다른 연결 / 가짜 커넥터: 커밋 응답을 받은 뒤 get(2 왕복, 뜻은 같다)
2089
2125
  qm.commit()
2090
2126
  return self.get(matchId, option)
2127
+ if _engine_qfast(version):
2128
+ # 0.12.0: 큐 전용 요청 코드를 아는 엔진(7.x, 리비전 3431 이상) - COMMIT_AND_GET 하나를 보내고 응답도 하나를 받는다
2129
+ return self._commit_and_get_code(matchId, option, send_raw)
2091
2130
  return self._commit_and_get_pipelined(matchId, option, send_raw, req[1])
2092
2131
 
2093
2132
  def commitAndGet(self, matchId: str | None = None, option: MatchOption = MatchOption.NONE) -> ILDataMsg:
2094
2133
  """:meth:`commit_and_get` 의 camelCase 별칭."""
2095
2134
  return self.commit_and_get(matchId, option)
2096
2135
 
2136
+ def _commit_and_get_frame(self, matchId: str | None, option: MatchOption) -> bytes:
2137
+ # 0.12.0: COMMIT_AND_GET 프레임. 칸은 GET 과 같고 코드만 다르다 - GET 캐시와 같은 열쇠(대기 시간 / 선택자 / 큐 이름)로 캐시한다
2138
+ ext = ILC.make_selector(matchId, option).encode("utf-8") if matchId else None
2139
+ wait = str(self.waitMsgTimeoutMS)
2140
+ c = self._cagCache
2141
+ if c is not None and c[0] == wait and c[1] == ext and c[2] == self.name:
2142
+ return c[3]
2143
+ frame = ILMsgUtil.create_request_msg_with_ext(
2144
+ ILC.MIMQ_COMMIT_AND_GET_REQUEST, ext, "", self.name, wait
2145
+ ).to_byte_array(True)
2146
+ self._cagCache = (wait, ext, self.name, frame)
2147
+ return frame
2148
+
2149
+ def _commit_and_get_code(self, matchId: str | None, option: MatchOption, send_raw) -> ILDataMsg:
2150
+ # 0.12.0: COMMIT_AND_GET(3402) 하나를 보내고 응답 하나를 읽는다(쥔 put 이 있으면 그 앞에 붙는다). 엔진이 커밋한 뒤 GET 을 돌린다.
2151
+ # 커밋이 실패하면 NOT_SUCCESSFUL_COMMIT 하나만 오고 GET 은 돌지 않았다 - ROLLBACK 을 보내 0.11.0 과 같은 상태로 끝내고 commit() 과
2152
+ # 같은 예외를 낸다. 응답 전에 끊기면 커밋 여부를 모른다 - commit() 처럼 올리고 재시도하지 않는다(모르는 구간이 GET 대기까지
2153
+ # 늘어난다, 자바 v2.8.0 과 같다)
2154
+ qm = self.qmgr
2155
+ conn = self.conn
2156
+ frame = self._commit_and_get_frame(matchId, option)
2157
+ try:
2158
+ with _io_lock_of(conn):
2159
+ qm.txnPending = False
2160
+ qm.set_last_access_time()
2161
+ send_raw(frame)
2162
+ res = conn.recv(self._get_recv_timeout())
2163
+ except _PASSTHROUGH_EXCEPTIONS:
2164
+ raise
2165
+ except Exception as exc:
2166
+ raise ILException(exc) from exc
2167
+ if res.getType() == ILC.MIMQ_REPORT_MESSAGE and res.getReportMsg().getCode() == ILC.MIMQ_NOT_SUCCESSFUL_COMMIT:
2168
+ # 커밋 거절. 엔진은 트랜잭션 오류면 롤백을 마쳤고 클러스터 정지면 트랜잭션을 남긴다 - 0.11.0 과 같은 끝 상태(커밋하려던 작업이
2169
+ # 모두 되돌아감)가 되도록 ROLLBACK 을 보낸다(거절 때만의 왕복 1 번, rollback() 은 예외를 올리지 않는다)
2170
+ qm.rollback()
2171
+ raise ILOperationException(res.getReportMsg().getArg2())
2172
+ # 커밋 확정. 여기부터는 get() 과 같다
2173
+ try:
2174
+ got = self._take_get_reply(res)
2175
+ except _PASSTHROUGH_EXCEPTIONS:
2176
+ raise
2177
+ except Exception as exc:
2178
+ raise ILException(exc) from exc
2179
+ if got is not None:
2180
+ return got
2181
+ if self.isInfiniteWaiting:
2182
+ return self.get(matchId, option) # 무한 대기 - get() 의 반복을 이어 간다
2183
+ raise ILNoMsgException(qm.get_name(), self.name)
2184
+
2097
2185
  def _commit_and_get_pipelined(self, matchId: str | None, option: MatchOption, send_raw, frame: bytes) -> ILDataMsg:
2098
2186
  # COMMIT + GET 을 sendall 한 번으로 보내고(쥔 put 이 있으면 그 앞에 붙는다) 응답 둘을 차례로 읽는다. 연결 잠금은 교환
2099
2187
  # 전체(실패 때의 ROLLBACK 포함) 동안 쥔다. 기록은 commit() + _get_once() 와 같게 - 보낼 때 txnPending 을 끄고,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jetstream-api
3
- Version: 0.11.0
3
+ Version: 0.12.0
4
4
  Summary: Python client API for iLink M.O.M. (Message Oriented Middleware)
5
5
  Author: snowjeans
6
6
  License: Boost Software License - Version 1.0 - August 17th, 2003
@@ -60,6 +60,18 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
60
60
  ## 설치 방법
61
61
  pip install jetstream-api
62
62
 
63
+ ## 0.12.0 변경 - 큐 전용 요청 코드(엔진 7.0.1.3431 이상) 자동 사용 (자바 v2.8.0 과 같음)
64
+
65
+ - **앱 코드는 바꿀 것이 없습니다.** 엔진 판 줄이 7.x 이고 리비전이 3431 이상이면 클라이언트가 스스로 새 요청 코드를 씁니다.
66
+ 그 밖의 엔진(6.3.x, 그보다 앞선 7.x, 5.x)에는 0.11.0 과 같은 요청을 보냅니다.
67
+ - **`commit_and_get`** 은 커밋 요청과 get 요청 대신 전용 요청 하나(COMMIT_AND_GET, 3402)를 보내고 응답도 하나만 받습니다.
68
+ 엔진이 커밋한 뒤 곧바로 get 을 돌립니다. 결과와 예외는 0.11.0 과 같습니다.
69
+ - 커밋이 거절되면 get 은 돌지 않았고, 롤백을 보내 커밋하려던 작업과 꺼낸 메시지를 큐에 되돌린 뒤 `ILOperationException` 을 올립니다.
70
+ - 응답을 받기 전에 연결이 끊기면 커밋 결과를 알 수 없습니다(재접속 / 재시도 없음). 커밋 결과가 get 결과와 한 응답으로 오므로
71
+ **결과를 알 수 없는 구간이 get 대기 시간까지** 늘어납니다.
72
+ - **`commit()`** 은 쥐고 있던 트랜잭션 put 이 **하나뿐**이면 put 과 커밋 대신 전용 요청 하나(PUT_AND_COMMIT, 3403)로 보냅니다.
73
+ 돌려주는 값과 예외는 같습니다. put 이 둘 이상이거나 `puts`, 64KiB 를 넘는 put, 쥔 것이 없을 때는 0.11.0 과 같습니다.
74
+
63
75
  ## 0.11.0 변경 - 큐 단건 put / get 가속, `commit_and_get` 추가
64
76
 
65
77
  - **새 API `ILQueue.commit_and_get(matchId=None, option=MatchOption.NONE)`** (camelCase 별칭 `commitAndGet`): 이 세션의
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jetstream-api"
7
- version = "0.11.0"
7
+ version = "0.12.0"
8
8
  description = "Python client API for iLink M.O.M. (Message Oriented Middleware)"
9
9
  authors = [{name = "snowjeans"}]
10
10
  readme = "README.md"
File without changes