jetstream-api 0.20.0__tar.gz → 0.20.1__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.
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/PKG-INFO +19 -1
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/README.md +18 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/__init__.py +1 -1
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/_qleader.py +48 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/properties.py +4 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/qmgr.py +65 -19
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/jetstream_api.egg-info/PKG-INFO +19 -1
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/pyproject.toml +1 -1
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/LICENSE.txt +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/_codec.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/_consumer.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/_groupwire.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/admin.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/admintopic.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/common.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/connectivity.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/exception.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/msg.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/partitioner.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/pattern.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/producer.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/py.typed +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/topic.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/ilink/util.py +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/jetstream_api.egg-info/SOURCES.txt +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/jetstream_api.egg-info/dependency_links.txt +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/jetstream_api.egg-info/requires.txt +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/jetstream_api.egg-info/top_level.txt +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/setup.cfg +0 -0
- {jetstream_api-0.20.0 → jetstream_api-0.20.1}/tests/test_example.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jetstream-api
|
|
3
|
-
Version: 0.20.
|
|
3
|
+
Version: 0.20.1
|
|
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,24 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
|
|
|
60
60
|
## 설치 방법
|
|
61
61
|
pip install jetstream-api
|
|
62
62
|
|
|
63
|
+
## 0.20.1 변경 - 큐 묶음 이동 중 재시도 (자바 v2.16.1 과 같음, 짝 엔진 7.0.1.3512 이상 - 묶음 이동은 7.0.1.3550 이상의 묶음 모드)
|
|
64
|
+
|
|
65
|
+
- 큐 묶음 이동(엔진 7.0.1.3550 3-b3, `ALTER QUEUE … LEADERGROUP` 등)이 진행 중이면 엔진이 그 큐의 요청을
|
|
66
|
+
`MIMQE_QUEUE_MOVING (<큐> -> group <새 묶음>)` 으로 거절합니다(요청 입구에서 작업 전 - 적용 안 됨 확정). 자동 확인 세션은 이것을
|
|
67
|
+
앱에 올리지 않고 100ms → 1초로 쉬며 리더를 다시 묻고 세션 타임아웃까지 다시 보냅니다(이동은 보통 1초 안팎). 끝내 이동이 안 끝나면
|
|
68
|
+
그 사유로 실패합니다. 트랜잭션 세션은 지금처럼 올립니다(커밋이면 엔진이 롤백 - 트랜잭션을 처음부터). 0.20.0 은 이 사유를 그대로
|
|
69
|
+
올렸습니다.
|
|
70
|
+
|
|
71
|
+
- 큐 속성 `leaderGroup` 문서: 큐가 하나도 없는 새 묶음으로 옮기면 첫 시도가
|
|
72
|
+
`MIMQE_QUEUE_MOVE_REFUSED (group <묶음> has no leader yet - retry)` 로 거절될 수 있습니다(엔진 7.0.1.3550 이상, 속성은 바뀌지
|
|
73
|
+
않음 - 함께 실린 다른 속성 변경도 적용되지 않는 요청 전체 거절). 관리 요청은 클라가 다시 보내지 않으니 몇 초 뒤 같은 객체로
|
|
74
|
+
`setQueueProperty` 를 다시 부릅니다. 클라 동작은 바뀌지 않습니다.
|
|
75
|
+
|
|
76
|
+
- 큐 자동 확인 세션의 `get` / `gets`: "at-most-once" 라고만 적었던 것을 "**한 번만 온다고 보장하지 않는다**" 로 고쳤습니다.
|
|
77
|
+
받는 도중 수신 시간이 다하면 다시 오지 않는 것(유실)은 그대로이고, 클러스터에서는 리더 장애 순간에 받은 메시지가 새 리더에서
|
|
78
|
+
**한 번 더** 올 수 있습니다(at-least-once - 엔진 큐 묶음 리더 판 7.0.1.3550 의 규칙, 2026-10-03 결정). 중복을 견뎌야 하면 메시지
|
|
79
|
+
ID 로 거르거나 트랜잭션 세션으로 받습니다. 클라 동작은 바뀌지 않습니다.
|
|
80
|
+
|
|
63
81
|
## 0.20.0 변경 - 큐 묶음 리더 라우팅, 큐 속성 leaderGroup (자바 v2.16.0 과 같음, 짝 엔진 7.0.1.3512 이상)
|
|
64
82
|
|
|
65
83
|
> 큐 묶음(LEADERGROUP) 라우팅은 엔진 **7.0.1.3540** 이상에서 묶음 모드가 켜졌을 때만 동작합니다(묶음 모드는 엔진 3-b3 에서 켜집니다).
|
|
@@ -10,6 +10,24 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
|
|
|
10
10
|
## 설치 방법
|
|
11
11
|
pip install jetstream-api
|
|
12
12
|
|
|
13
|
+
## 0.20.1 변경 - 큐 묶음 이동 중 재시도 (자바 v2.16.1 과 같음, 짝 엔진 7.0.1.3512 이상 - 묶음 이동은 7.0.1.3550 이상의 묶음 모드)
|
|
14
|
+
|
|
15
|
+
- 큐 묶음 이동(엔진 7.0.1.3550 3-b3, `ALTER QUEUE … LEADERGROUP` 등)이 진행 중이면 엔진이 그 큐의 요청을
|
|
16
|
+
`MIMQE_QUEUE_MOVING (<큐> -> group <새 묶음>)` 으로 거절합니다(요청 입구에서 작업 전 - 적용 안 됨 확정). 자동 확인 세션은 이것을
|
|
17
|
+
앱에 올리지 않고 100ms → 1초로 쉬며 리더를 다시 묻고 세션 타임아웃까지 다시 보냅니다(이동은 보통 1초 안팎). 끝내 이동이 안 끝나면
|
|
18
|
+
그 사유로 실패합니다. 트랜잭션 세션은 지금처럼 올립니다(커밋이면 엔진이 롤백 - 트랜잭션을 처음부터). 0.20.0 은 이 사유를 그대로
|
|
19
|
+
올렸습니다.
|
|
20
|
+
|
|
21
|
+
- 큐 속성 `leaderGroup` 문서: 큐가 하나도 없는 새 묶음으로 옮기면 첫 시도가
|
|
22
|
+
`MIMQE_QUEUE_MOVE_REFUSED (group <묶음> has no leader yet - retry)` 로 거절될 수 있습니다(엔진 7.0.1.3550 이상, 속성은 바뀌지
|
|
23
|
+
않음 - 함께 실린 다른 속성 변경도 적용되지 않는 요청 전체 거절). 관리 요청은 클라가 다시 보내지 않으니 몇 초 뒤 같은 객체로
|
|
24
|
+
`setQueueProperty` 를 다시 부릅니다. 클라 동작은 바뀌지 않습니다.
|
|
25
|
+
|
|
26
|
+
- 큐 자동 확인 세션의 `get` / `gets`: "at-most-once" 라고만 적었던 것을 "**한 번만 온다고 보장하지 않는다**" 로 고쳤습니다.
|
|
27
|
+
받는 도중 수신 시간이 다하면 다시 오지 않는 것(유실)은 그대로이고, 클러스터에서는 리더 장애 순간에 받은 메시지가 새 리더에서
|
|
28
|
+
**한 번 더** 올 수 있습니다(at-least-once - 엔진 큐 묶음 리더 판 7.0.1.3550 의 규칙, 2026-10-03 결정). 중복을 견뎌야 하면 메시지
|
|
29
|
+
ID 로 거르거나 트랜잭션 세션으로 받습니다. 클라 동작은 바뀌지 않습니다.
|
|
30
|
+
|
|
13
31
|
## 0.20.0 변경 - 큐 묶음 리더 라우팅, 큐 속성 leaderGroup (자바 v2.16.0 과 같음, 짝 엔진 7.0.1.3512 이상)
|
|
14
32
|
|
|
15
33
|
> 큐 묶음(LEADERGROUP) 라우팅은 엔진 **7.0.1.3540** 이상에서 묶음 모드가 켜졌을 때만 동작합니다(묶음 모드는 엔진 3-b3 에서 켜집니다).
|
|
@@ -108,6 +108,34 @@ def follower_hint(reason: str):
|
|
|
108
108
|
return (tok, nid)
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
def is_moving(reason: str) -> bool:
|
|
112
|
+
"""큐 묶음 이동 중 거절인가(0.20.1, 엔진 3-b3).
|
|
113
|
+
|
|
114
|
+
``MIMQE_QUEUE_MOVING (<큐> -> group <새 묶음>)`` / ``(... (node leader))`` / ``(retry shortly)``. 엔진은 요청 입구에서 작업 전에
|
|
115
|
+
거절하므로 **그 요청은 적용되지 않았다**(엔진 확인). 리더 힌트는 없다 - 이동이 끝난 뒤 3397 "Q" 로 다시 묻는다. 이동은 보통
|
|
116
|
+
1초 안팎, 최악이면 수십 초다.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
reason (str): 엔진 사유(arg2).
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
bool: 이동 중 거절이면 True.
|
|
123
|
+
"""
|
|
124
|
+
return bool(reason) and reason.startswith("MIMQE_QUEUE_MOVING (")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def route_rejected(reason: str) -> bool:
|
|
128
|
+
"""라우팅 거절(적용 안 됨 확정)인가 - 요청 단위 팔로워 거절 또는 묶음 이동 중.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
reason (str): 엔진 사유(arg2).
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
bool: 둘 중 하나면 True.
|
|
135
|
+
"""
|
|
136
|
+
return follower_hint(reason) is not None or is_moving(reason)
|
|
137
|
+
|
|
138
|
+
|
|
111
139
|
def cross_error(have: str, want: str) -> ILOperationException:
|
|
112
140
|
"""한 트랜잭션에 다른 묶음 큐를 섞으려 할 때의 오류(엔진 사유와 같은 머리).
|
|
113
141
|
|
|
@@ -315,6 +343,26 @@ class QueueRouter:
|
|
|
315
343
|
self.lookup([name])
|
|
316
344
|
return True
|
|
317
345
|
|
|
346
|
+
def forget_queue(self, name: str) -> None:
|
|
347
|
+
"""그 큐의 묶음 소속만 버린다 - 묶음 이동으로 소속이 바뀔 때. 다음 요청이 다시 묻는다.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
name (str): 큐 이름.
|
|
351
|
+
"""
|
|
352
|
+
with self.lock:
|
|
353
|
+
self.q_group.pop(name, None)
|
|
354
|
+
|
|
355
|
+
def on_moving(self, name: str, pause: float) -> None:
|
|
356
|
+
"""묶음 이동 중 거절을 받았다 - 소속을 버리고 ``pause`` 초 쉰 뒤 다시 묻는다(0.20.1).
|
|
357
|
+
|
|
358
|
+
Args:
|
|
359
|
+
name (str): 큐 이름.
|
|
360
|
+
pause (float): 쉴 시간(초).
|
|
361
|
+
"""
|
|
362
|
+
self.forget_queue(name)
|
|
363
|
+
time.sleep(pause)
|
|
364
|
+
self.lookup([name])
|
|
365
|
+
|
|
318
366
|
def forget_group(self, grp: str | None) -> None:
|
|
319
367
|
"""그 묶음의 리더와 그 묶음 큐들의 소속을 버린다 - 다음 요청이 다시 묻는다.
|
|
320
368
|
|
|
@@ -760,6 +760,10 @@ class ILQueueProperty(_AutoAccessor):
|
|
|
760
760
|
:meth:`ILAdminQmgr.setQueueProperty` 하면 엔진의 저장값이 그대로다(다른 필드와 달리 덮어쓰지 않는다,
|
|
761
761
|
묶음이 바뀌면 큐 리더가 옮겨 가기 때문이다). 묶음을 풀려면 ``""`` 를 **지정**한다. 글자 규칙(영숫자
|
|
762
762
|
``.`` ``_`` ``-``)과 지정할 수 없는 큐(SYSTEM. / DLQ / XMITQ / REMOTE)는 엔진이 ``MIMQE_INVALID_PROPERTY`` 로 거절한다.
|
|
763
|
+
큐가 하나도 없는 새 묶음으로 옮기면 그 묶음의 리더가 아직 없어 첫 시도가
|
|
764
|
+
``MIMQE_QUEUE_MOVE_REFUSED (group <묶음> has no leader yet - retry)`` 로 거절될 수 있다(엔진 7.0.1.3550 이상, 속성은
|
|
765
|
+
바뀌지 않는다 - 함께 실린 다른 속성 변경도 적용되지 않는다, 요청 전체 거절). 클라는 관리 요청을 다시 보내지 않으니 몇 초 뒤
|
|
766
|
+
같은 객체로 ``setQueueProperty`` 를 다시 부른다.
|
|
763
767
|
스펙: 기본 "" · 범위 47바이트 이하 문자열 · 변경 가능 · 엔진 7.0.1.3535 이상(그 전 엔진은 무시한다).
|
|
764
768
|
legacyBlob (bool): 이 객체가 **구버전(4096) 블롭**에서 만들어졌는지.
|
|
765
769
|
엔진 rev 3155 미만이 보낸 응답이면 True 다. 그 경우 ``expiry`` /
|
|
@@ -109,7 +109,7 @@ def _engine_qfast(version: str) -> bool:
|
|
|
109
109
|
return m is not None and int(m.group(1)) == 7 and int(m.group(4)) >= _QUEUE_FAST_REVISION
|
|
110
110
|
|
|
111
111
|
|
|
112
|
-
from ._qleader import QueueRouter, follower_hint # noqa: E402
|
|
112
|
+
from ._qleader import QueueRouter, follower_hint, is_moving, route_rejected # noqa: E402
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
def _router_of(qm) -> "QueueRouter | None":
|
|
@@ -711,7 +711,7 @@ class ILQmgr:
|
|
|
711
711
|
# 0.20.0: 커밋이 팔로워 거절로 실패했다 - 트랜잭션 도중 묶음 리더가 바뀌었다. 그 묶음 캐시를 버린다(트랜잭션 PUT 은
|
|
712
712
|
# 답이 없어 여기서야 안다 - 안 버리면 다음 트랜잭션도 옛 리더로 간다)
|
|
713
713
|
r = self._qrouter
|
|
714
|
-
if r is not None and
|
|
714
|
+
if r is not None and route_rejected(reason or ""):
|
|
715
715
|
r.forget_group(r.trx_group)
|
|
716
716
|
|
|
717
717
|
def rollback(self) -> int:
|
|
@@ -1789,6 +1789,8 @@ class ILQueue:
|
|
|
1789
1789
|
#: 0.20.0: 마지막 요청을 보낸 세션(부모 또는 큐 링크)과 그 큐의 묶음
|
|
1790
1790
|
self._sess = qmgr
|
|
1791
1791
|
self._group: str | None = None
|
|
1792
|
+
#: 0.20.1: 묶음 이동 중 다시 묻기 전에 쉬는 시간(초) - 100ms 부터 두 배씩 1초까지
|
|
1793
|
+
self._move_pause = 0.1
|
|
1792
1794
|
|
|
1793
1795
|
if not existCheck:
|
|
1794
1796
|
return
|
|
@@ -1918,6 +1920,14 @@ class ILQueue:
|
|
|
1918
1920
|
r.on_link_error(sess)
|
|
1919
1921
|
return qm.is_auto_commit()
|
|
1920
1922
|
reason = _reason_of(exc)
|
|
1923
|
+
if is_moving(reason):
|
|
1924
|
+
# 0.20.1: 묶음 이동 중(적용 안 됨 확정, 엔진 3-b3). 소속이 바뀌므로 그 큐 소속을 버리고 쉬었다가 다시 묻는다
|
|
1925
|
+
if not qm.is_auto_commit():
|
|
1926
|
+
r.forget_queue(self.name)
|
|
1927
|
+
return False
|
|
1928
|
+
r.on_moving(self.name, self._move_pause)
|
|
1929
|
+
self._move_pause = min(self._move_pause * 2, 1.0)
|
|
1930
|
+
return True
|
|
1921
1931
|
if follower_hint(reason) is None:
|
|
1922
1932
|
return False
|
|
1923
1933
|
if not qm.is_auto_commit():
|
|
@@ -1925,12 +1935,39 @@ class ILQueue:
|
|
|
1925
1935
|
return False
|
|
1926
1936
|
return r.on_reject(self.name, reason)
|
|
1927
1937
|
|
|
1938
|
+
def _retry_routed(self, exc: BaseException, fn):
|
|
1939
|
+
# 0.20.1: 라우팅 실패면 다시 보낸다. 묶음 이동 중(QUEUE_MOVING)이나 그 뒤의 팔로워 거절이 이어지면 자동 확인 세션은
|
|
1940
|
+
# 세션 타임아웃까지 되풀이한다(둘 다 적용 안 됨 확정). 라우팅 실패가 아니면 (False, None)
|
|
1941
|
+
self._move_pause = 0.1
|
|
1942
|
+
if not self._reroute(exc):
|
|
1943
|
+
return False, None
|
|
1944
|
+
deadline = None
|
|
1945
|
+
while True:
|
|
1946
|
+
try:
|
|
1947
|
+
return True, fn()
|
|
1948
|
+
except ILNoMsgException:
|
|
1949
|
+
raise
|
|
1950
|
+
except Exception as e2:
|
|
1951
|
+
qm = self.qmgr
|
|
1952
|
+
if not qm.is_auto_commit() or not route_rejected(_reason_of(e2)):
|
|
1953
|
+
raise
|
|
1954
|
+
now = time.monotonic()
|
|
1955
|
+
if deadline is None:
|
|
1956
|
+
st = qm.get_session_timeout()
|
|
1957
|
+
deadline = now + (st / 1000.0 if st and st > 0 else 30.0)
|
|
1958
|
+
if now >= deadline:
|
|
1959
|
+
raise
|
|
1960
|
+
self._move_pause = min(self._move_pause, deadline - now) # 쉬는 시간이 시한을 넘지 않게
|
|
1961
|
+
if not self._reroute(e2):
|
|
1962
|
+
raise
|
|
1963
|
+
|
|
1928
1964
|
def _put_msg(self, msg: ILDataMsg) -> str:
|
|
1929
1965
|
try:
|
|
1930
1966
|
return self._put_msg_once(msg)
|
|
1931
1967
|
except Exception as exc:
|
|
1932
|
-
|
|
1933
|
-
|
|
1968
|
+
done, val = self._retry_routed(exc, lambda: self._put_msg_once(msg))
|
|
1969
|
+
if done:
|
|
1970
|
+
return val
|
|
1934
1971
|
# 예외에 리더 힌트가 실려 있으면 **되던지기 전에** 캐시에 남긴다 -
|
|
1935
1972
|
# 미커밋 트랜잭션 때문에 여기서 예외를 올리더라도, 앱이 뒤이어
|
|
1936
1973
|
# reconnect 를 부를 때 그 주소를 후보로 쓸 수 있어야 한다.
|
|
@@ -2017,8 +2054,9 @@ class ILQueue:
|
|
|
2017
2054
|
try:
|
|
2018
2055
|
return self._puts_once(msgs)
|
|
2019
2056
|
except Exception as exc:
|
|
2020
|
-
|
|
2021
|
-
|
|
2057
|
+
done, val = self._retry_routed(exc, lambda: self._puts_once(msgs))
|
|
2058
|
+
if done:
|
|
2059
|
+
return val
|
|
2022
2060
|
raise
|
|
2023
2061
|
|
|
2024
2062
|
def _puts_once(self, msgs: List[ILDataMsg]) -> List[str]:
|
|
@@ -2144,10 +2182,15 @@ class ILQueue:
|
|
|
2144
2182
|
왕복이 한 번씩 더 든다 - 핸들을 재사용하거나 ``access_queue(name, exist_check=False)`` 로 얻는다.
|
|
2145
2183
|
``ILQmgr`` 는 스레드 안전하지 않으므로 **스레드마다 ILQmgr 를 따로** 둔다.
|
|
2146
2184
|
|
|
2147
|
-
자동 확인 세션의 get 은 엔진이 보내는 순간 꺼낸 것으로
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2185
|
+
자동 확인 세션의 get 은 엔진이 보내는 순간 꺼낸 것으로 친다. 그래서 **한 번만 온다고 보장하지 않는다**
|
|
2186
|
+
(두 방향 다 있다):
|
|
2187
|
+
|
|
2188
|
+
* 큰 메시지를 받는 도중 수신 시간(세션 타임아웃, 대기 시간이 더 길면 그 2배)이 다하면 연결을 닫고
|
|
2189
|
+
(다시 붙여야 한다) 그 메시지는 다시 오지 않는다. 큰 메시지는 세션 타임아웃을 넉넉히 두거나
|
|
2190
|
+
트랜잭션 세션으로 받는다.
|
|
2191
|
+
* 클러스터에서는 리더 장애 순간에 받은 메시지가 새 리더에서 **한 번 더** 올 수 있다(at-least-once -
|
|
2192
|
+
엔진 큐 묶음 리더 판의 규칙, 2026-10-03 결정). 중복을 견뎌야 하면 메시지 ID 로 거르거나 트랜잭션
|
|
2193
|
+
세션으로 받아 처리한 뒤 커밋한다.
|
|
2151
2194
|
|
|
2152
2195
|
Example::
|
|
2153
2196
|
|
|
@@ -2162,8 +2205,9 @@ class ILQueue:
|
|
|
2162
2205
|
except ILNoMsgException:
|
|
2163
2206
|
raise
|
|
2164
2207
|
except Exception as exc:
|
|
2165
|
-
|
|
2166
|
-
|
|
2208
|
+
done, val = self._retry_routed(exc, lambda: self._get_once(matchId, option))
|
|
2209
|
+
if done:
|
|
2210
|
+
return val
|
|
2167
2211
|
# 예외에 리더 힌트가 실려 있으면 **되던지기 전에** 캐시에 남긴다 -
|
|
2168
2212
|
# 미커밋 트랜잭션 때문에 여기서 예외를 올리더라도, 앱이 뒤이어
|
|
2169
2213
|
# reconnect 를 부를 때 그 주소를 후보로 쓸 수 있어야 한다.
|
|
@@ -2373,7 +2417,7 @@ class ILQueue:
|
|
|
2373
2417
|
# 커밋 거절. 엔진은 트랜잭션 오류면 롤백을 마쳤고 클러스터 정지면 트랜잭션을 남긴다 - 0.11.0 과 같은 끝 상태(커밋하려던 작업이
|
|
2374
2418
|
# 모두 되돌아감)가 되도록 ROLLBACK 을 보낸다(거절 때만의 왕복 1 번, rollback() 은 예외를 올리지 않는다)
|
|
2375
2419
|
r = getattr(qm, "_qrouter", None)
|
|
2376
|
-
if r is not None and
|
|
2420
|
+
if r is not None and route_rejected(res.getReportMsg().getArg2() or ""):
|
|
2377
2421
|
r.forget_group(self._group)
|
|
2378
2422
|
qm.rollback()
|
|
2379
2423
|
raise ILOperationException(res.getReportMsg().getArg2())
|
|
@@ -2436,7 +2480,7 @@ class ILQueue:
|
|
|
2436
2480
|
if commit_res.getType() != ILC.MIMQ_REPORT_MESSAGE:
|
|
2437
2481
|
raise ILMsgTypeException(commit_res.getType(), " msg type must be [MIMQ_REPORT_MESSAGE]")
|
|
2438
2482
|
r = getattr(qm, "_qrouter", None)
|
|
2439
|
-
if r is not None and
|
|
2483
|
+
if r is not None and route_rejected(commit_res.getReportMsg().getArg2() or ""):
|
|
2440
2484
|
r.forget_group(self._group)
|
|
2441
2485
|
raise ILOperationException(commit_res.getReportMsg().getArg2())
|
|
2442
2486
|
|
|
@@ -2479,9 +2523,10 @@ class ILQueue:
|
|
|
2479
2523
|
|
|
2480
2524
|
Note:
|
|
2481
2525
|
건별 :meth:`get` 보다 왕복이 적어 대량 소비에 유리하다.
|
|
2482
|
-
트랜잭션 세션이면 커밋 전까지 확정되지 않는다. 자동 확인 세션은
|
|
2483
|
-
수신 시간이 다하면 연결을 닫고 그 묶음은 다시 오지
|
|
2484
|
-
|
|
2526
|
+
트랜잭션 세션이면 커밋 전까지 확정되지 않는다. 자동 확인 세션은 한 번만 온다고 보장하지 않는다
|
|
2527
|
+
(:meth:`get` 참조) - 받는 도중 수신 시간이 다하면 연결을 닫고 그 묶음은 다시 오지 않고, 클러스터의
|
|
2528
|
+
리더 장애 순간에 받은 묶음은 새 리더에서 한 번 더 올 수 있다. 큰 묶음은 세션 타임아웃을 넉넉히
|
|
2529
|
+
두거나 트랜잭션 세션으로 받는다.
|
|
2485
2530
|
|
|
2486
2531
|
Example::
|
|
2487
2532
|
|
|
@@ -2493,8 +2538,9 @@ class ILQueue:
|
|
|
2493
2538
|
except ILNoMsgException:
|
|
2494
2539
|
raise
|
|
2495
2540
|
except Exception as exc:
|
|
2496
|
-
|
|
2497
|
-
|
|
2541
|
+
done, val = self._retry_routed(exc, lambda: self._gets_once(max_count))
|
|
2542
|
+
if done:
|
|
2543
|
+
return val
|
|
2498
2544
|
raise
|
|
2499
2545
|
|
|
2500
2546
|
def _gets_once(self, max_count: int) -> List[ILDataMsg]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jetstream-api
|
|
3
|
-
Version: 0.20.
|
|
3
|
+
Version: 0.20.1
|
|
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,24 @@ lz4 배치 압축을 쓰려면 `pip install "jetstream-api[lz4]"`, zstd 배치
|
|
|
60
60
|
## 설치 방법
|
|
61
61
|
pip install jetstream-api
|
|
62
62
|
|
|
63
|
+
## 0.20.1 변경 - 큐 묶음 이동 중 재시도 (자바 v2.16.1 과 같음, 짝 엔진 7.0.1.3512 이상 - 묶음 이동은 7.0.1.3550 이상의 묶음 모드)
|
|
64
|
+
|
|
65
|
+
- 큐 묶음 이동(엔진 7.0.1.3550 3-b3, `ALTER QUEUE … LEADERGROUP` 등)이 진행 중이면 엔진이 그 큐의 요청을
|
|
66
|
+
`MIMQE_QUEUE_MOVING (<큐> -> group <새 묶음>)` 으로 거절합니다(요청 입구에서 작업 전 - 적용 안 됨 확정). 자동 확인 세션은 이것을
|
|
67
|
+
앱에 올리지 않고 100ms → 1초로 쉬며 리더를 다시 묻고 세션 타임아웃까지 다시 보냅니다(이동은 보통 1초 안팎). 끝내 이동이 안 끝나면
|
|
68
|
+
그 사유로 실패합니다. 트랜잭션 세션은 지금처럼 올립니다(커밋이면 엔진이 롤백 - 트랜잭션을 처음부터). 0.20.0 은 이 사유를 그대로
|
|
69
|
+
올렸습니다.
|
|
70
|
+
|
|
71
|
+
- 큐 속성 `leaderGroup` 문서: 큐가 하나도 없는 새 묶음으로 옮기면 첫 시도가
|
|
72
|
+
`MIMQE_QUEUE_MOVE_REFUSED (group <묶음> has no leader yet - retry)` 로 거절될 수 있습니다(엔진 7.0.1.3550 이상, 속성은 바뀌지
|
|
73
|
+
않음 - 함께 실린 다른 속성 변경도 적용되지 않는 요청 전체 거절). 관리 요청은 클라가 다시 보내지 않으니 몇 초 뒤 같은 객체로
|
|
74
|
+
`setQueueProperty` 를 다시 부릅니다. 클라 동작은 바뀌지 않습니다.
|
|
75
|
+
|
|
76
|
+
- 큐 자동 확인 세션의 `get` / `gets`: "at-most-once" 라고만 적었던 것을 "**한 번만 온다고 보장하지 않는다**" 로 고쳤습니다.
|
|
77
|
+
받는 도중 수신 시간이 다하면 다시 오지 않는 것(유실)은 그대로이고, 클러스터에서는 리더 장애 순간에 받은 메시지가 새 리더에서
|
|
78
|
+
**한 번 더** 올 수 있습니다(at-least-once - 엔진 큐 묶음 리더 판 7.0.1.3550 의 규칙, 2026-10-03 결정). 중복을 견뎌야 하면 메시지
|
|
79
|
+
ID 로 거르거나 트랜잭션 세션으로 받습니다. 클라 동작은 바뀌지 않습니다.
|
|
80
|
+
|
|
63
81
|
## 0.20.0 변경 - 큐 묶음 리더 라우팅, 큐 속성 leaderGroup (자바 v2.16.0 과 같음, 짝 엔진 7.0.1.3512 이상)
|
|
64
82
|
|
|
65
83
|
> 큐 묶음(LEADERGROUP) 라우팅은 엔진 **7.0.1.3540** 이상에서 묶음 모드가 켜졌을 때만 동작합니다(묶음 모드는 엔진 3-b3 에서 켜집니다).
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|