콘텐츠로 이동

한국어 | English

레퍼런스 목차

04. Eventing

이 category는 socket monitoring, 재사용 가능한 poller, standalone timer를 다룬다 — 각각 socket_t::monitor_open(...)(Sockets category)와 직접 생성(poller_t, timer_t)으로 만들어진다. 이 투영엔 Zlink.CreatePoller()/CreateTimer() 스타일의 factory가 없다. 정확한 signature는 Contracts/Eventing/가 소유한다.


socket_monitor_t

socket의 connection lifecycle event를 관찰하고 현재 상태를 읽는다.

zlink::socket_monitor_t monitor =
    zlink::socket_monitor_t::open (socket, zlink::monitor_event::connected | zlink::monitor_event::disconnected);
auto event = monitor.recv (zlink::recv_flags_t::none);
zlink::monitor_status_t status = monitor.status ();

옵션.

Member 기본값 의미
socket_monitor_t() 기본, 대입 전까지 invalid
open(const socket_t&, monitor_event) monitor_event::all static — 실제 생성 경로, 내부적으로 socket_t::monitor_open(...)이 호출
valid() 이 monitor가 아직 사용 가능한지
recv(recv_flags_t) recv_flags_t::none 유일한 event delivery 경로, 다음 queued lifecycle event pull
recv(recv_flags_t) recv_flags_t::none 다음 event를 가져옴; std::optional<monitor_event_t> 반환
status() const monitor 대상 socket 상태의 시점 스냅샷, monitor_status_t 반환
close() monitor의 native resource를 해제
move 생성/대입 caller-owned monitor resource 이전

완료 결과. 모든 member는 동기다. move-only다 — 소멸자는 암묵적으로 close하지 않는다.

선택 기준. pull 기반 lifecycle-event drain loop엔 recv를 쓰고 시점 스냅샷엔 status()를 쓴다.


monitor_status_t

socket_monitor_t::status()가 반환하는, socket의 monitored 상태와 auto-high-water-mark telemetry 스냅샷. accessor method가 있는 class가 아니라 순수 struct다(dotnet의 MonitorStatus와 다름) — 모든 필드가 public 데이터다.

옵션. 인자 없음 — status()로 생성하지 직접 생성하지 않는다.

그룹 필드
ABI identity abi_version, struct_size(uint32_t)
Source/state source_kind(monitor_source_kind), state_flags/detail_flags(uint32_t 비트마스크 — 아래 enum 참고), is_ready()(계산값: (state_flags & 1) != 0)
Pending count snd_pending_msgs, rcv_pending_msgs(uint64_t)
Auto-HWM 설정 auto_hwm_enabled(bool), auto_hwm_profile, auto_hwm_role, auto_hwm_policy_class(uint32_tzlink::auto_hwm_profile enum 타입이 아니라 raw 정수 필드), auto_hwm_unit_budget_bytes, auto_hwm_socket_message_slots(uint64_t), auto_hwm_size_cap(uint32_t)
Connection bucket auto_hwm_connection_bucket_enabled(bool), auto_hwm_connection_bucket_count/_index/_hwm_4k(uint32_t), auto_hwm_connection_bucket_hysteresis_retained(bool)
Auto-HWM plan(byte) auto_hwm_effective_message_bytes, auto_hwm_planned_sndhwm_bytes/_rcvhwm_bytes, auto_hwm_applied_sndhwm_bytes/_rcvhwm_bytes(uint64_t), auto_hwm_effective_sndbuf/_rcvbuf(int32_t)
Auto-HWM recalc auto_hwm_last_recalc_ms(uint64_t), auto_hwm_last_recalc_reason(uint32_t), auto_hwm_send_blocked_ratio_ppm(uint32_t)
Auto-HWM deferred shrink auto_hwm_deferred_sndhwm_bytes/_rcvhwm_bytes(uint64_t, 대응하는 ..._valid bool이 true일 때만 유효)
In-flight/과금 snd_bytes_in_flight, rcv_bytes_in_flight, minimum_core_message_charge_bytes, oversize_message_admission_count, oversize_message_admission_max_bytes(uint64_t)

완료 결과. 해당 없음 — 순수 데이터, dispose 없음.

선택 기준. state_flags를 직접 디코딩하는 대신 is_ready()를 읽는다. socket의 실제 send/receive HWM이 설정한 common_socket_options_t 값(Sockets category)과 다른 이유를 진단할 땐 connection-bucket과 auto-HWM-plan 필드를 쓴다.


poller_t

socket, file descriptor, monitor, timer를 하나의 재사용 가능한 wait로 multiplex한다.

zlink::poller_t poller;
poller.add (dealer, zlink::poll_event_flag_t::pollin, /*slot=*/1);
poller.add (timer, /*slot=*/2);
std::vector<zlink::poll_event_t> ready (8);
size_t count = poller.wait (ready.data (), ready.size (), std::chrono::seconds (1));

옵션.

Member 기본값 의미
add(socket_monitor_t&, poll_event_flag_t, std::uintptr_t slot_) monitor를 주어진 event로 등록; slot_은 대응하는 poll_event_t로 되돌아옴
add(socket_t&, poll_event_flag_t, std::uintptr_t slot_) 같은 방식으로 socket을 등록
add_fd(int fd_, poll_event_flag_t, std::uintptr_t slot_) 같은 방식으로 raw file descriptor를 등록
add(timer_t&, std::uintptr_t slot_) timer를 등록, fire하면 ready로 표시
modify_fd(int, poll_event_flag_t) / modify(socket_monitor_t&, poll_event_flag_t) / modify(socket_t&, poll_event_flag_t) 이미 등록된 source의 감시 event를 변경
remove(socket_monitor_t&) / remove(socket_t&) / remove(timer_t&) / remove_fd(int) 등록 해제; 각각 bool 반환, 등록돼 있었으면 true
size() const 현재 등록된 source 개수(int)
close() poller의 native resource를 해제
wait(poll_event_t* events_, size_t capacity_, std::chrono::milliseconds timeout_) source 하나 이상이 ready 상태이거나 timeout_이 지날 때까지 block

완료 결과. 등록/제거 member는 동기다. waittimeout_까지 block하며, capacity_까지 결과를 쓰고 쓴 개수를 반환한다(timeout이면 0). poller_tsocket_monitor_t&도 직접 등록할 수 있다(dotnet의 IPollerAdd overload는 IZlinkSocket/IZlinkTimer만 받고, monitor는 대신 ZlinkPoll.Poll(IReadOnlyList<ISocketMonitor>, ...)을 통해 간접적으로 poll되는 것과 다르다).

선택 기준. 서비스 수명 전체에서 poller 하나를 쓴다. 감시하는 event만 바뀔 땐 remove + add 대신 modify를 선호한다.


poll_event_t

poller_t::wait 호출이 보고하는 준비된 source 하나. 순수 struct이며 기본 생성 시 source_kind = poll_source_kind_t::socket이다.

옵션.

Member 타입 의미
source_kind poll_source_kind_t socket/fd/timer
slot std::uintptr_t 등록 시 제공한 caller token
revents poll_event_flag_t 실제로 발생한 event
fd int fd kind source에서만 채워짐

완료 결과. 해당 없음 — 순수 데이터.

선택 기준. source_kind/slot으로 분기해 각 wait 결과를 대응하는 socket·descriptor·timer로 연결한다.


poll_item_t / zlink::poll(...)

poller_t와 구별되는 standalone one-shot poll helper — 아무것도 영구적으로 등록하지 않고 watch item의 순수 배열을 만들어 한 번 기다린다.

std::vector<zlink::poll_item_t> items {
    zlink::poll_item_t::from_socket (dealer, zlink::poll_event_flag_t::pollin),
    zlink::poll_item_t::from_fd (raw_fd, zlink::poll_event_flag_t::pollin),
};
int ready = zlink::poll (items, std::chrono::milliseconds (1000));

옵션.

Member 의미
socket(socket_t*) poll할 socket, fd 기반 item이면 null
fd(int) socket이 null일 때 poll할 file descriptor
events/revents(poll_event_flag_t) 요청한/실제로 발생한 event
from_socket(socket_t&, poll_event_flag_t) / from_fd(int, poll_event_flag_t) socket이나 raw fd용 poll_item_t를 만드는 static factory
zlink::poll(poll_item_t* items_, size_t count_, std::chrono::milliseconds timeout_) items_ 전체를 한 번 기다리며 revents를 그 자리에 씀; std::vector<poll_item_t>& 편의 overload도 있음

완료 결과. 동기다. 준비된 item 개수를 반환한다(timeout이면 0). 각 poll_item_trevents는 호출로 그 자리에서 쓰인다.

선택 기준. 작고 고정된 집합에 대한 임시 one-off wait엔 이 자유 함수 형태를 쓴다. 감시 대상 집합이 시간에 따라 바뀌거나 monitor/timer를 socket과 함께 multiplex해야 할 땐 poller_t를 쓴다.


timer_t

interval마다 fire하며 (recv로) poll하거나 poller를 통해 구동할 수 있는 standalone timer.

zlink::timer_t timer;
timer.start (std::chrono::seconds (1), /*repeat_count=*/0);
auto count = timer.recv ();

옵션.

Member 기본값 의미
start(duration, uint64_t repeat_count_) repeat_count_ = 0 duration마다 fire를 시작(임의 std::chrono::duration을 받는 template, 내부적으로 나노초로 변환; 음수는 config_error_t{invalid_argument}); repeat_count_가 횟수 상한
stop() fire를 멈춤; start로 재시작 가능
recv() 누적 fire count를 가져옴; std::optional<uint64_t> 반환, 대기 중인 게 없으면 std::nullopt
valid() 이 timer가 아직 사용 가능한지
close() timer의 native resource를 해제

완료 결과. 모든 member는 동기다. move-only다 — 소멸자는 암묵적으로 close하지 않는다.

선택 기준. 만료를 pull하려면 recv를, socket과 함께 multiplex하려면 poller_t::add(timer_t&, std::uintptr_t)로 등록한다.


Eventing enum

위 모든 항목에서 참조하는 공유 enum.

Enum 사용처
monitor_event socket_monitor_t::open/monitor_event_t::event connected, connect_delayed, connect_retried, listening, bind_failed, accepted, accept_failed, closed, close_failed, disconnected, monitor_stopped, handshake_failed_no_detail, connection_ready, handshake_failed_protocol, handshake_failed_auth, peer_weight_changed, all
monitor_target_kind_t 이 category에 문서화된 어떤 항목으로도 도달하지 않음 socket, discovery, spot — 뒤 둘은 이 레퍼런스 tier에서 대응하는 public monitor 생성 진입점이 없다
monitor_source_kind monitor_status_t::source_kind socket(1), spot_pub(3), spot_sub(4) — 뒤 둘은 선언돼 있지만 monitor_target_kind_t::spot처럼 bindings 계층에서 도달 가능한 public source가 없다(SPOT/Actor는 framework 계층에만 존재)
monitor_state monitor_status_t::state_flags(비트마스크) ready(1), bound_ready(2), closed(8)
monitor_status_detail monitor_status_t::detail_flags(비트마스크) snd_pending_msgs(2), rcv_pending_msgs(4)
disconnect_reason 이 category에 문서화된 어떤 항목으로도 도달하지 않음 unknown, handshake_failed, transport_error, ctx_term
poll_source_kind_t poll_event_t::source_kind socket, fd, timer
poll_event_flag_t poller_t::add/modify/wait, poll_item_t, zlink::poll none, pollin, pollout, pollerr, pollcompletion(이 투영엔 dotnet의 PollEventFlags.PollPri에 대응하는 pollpri가 없다)

선택 기준. monitor_source_kind::spot_pub/spot_sub, monitor_target_kind_t::spot/discovery, disconnect_reason은 이 bindings 계층의 public 진입점에서 선언은 됐지만 현재 도달 불가능한 것으로 취급한다 — 오늘 application 코드에서 우회할 대상이 아니라 스펙 차원의 질문이다.


Contracts/Eventing/C++ 바인딩 스펙에서 전체 근거를 확인한다.