latest (dev)
Copy
Latest development documentation · Updated 2026-10-08
Source code for tensorplay.distributed.elastic.events.api
"""Structured event records emitted by the agent and workers."""
from __future__ import annotations
import json
import time
from dataclasses import asdict, dataclass, field
from enum import Enum
from typing import Any, Union
__all__ = ["EventSource", "Event", "NodeState", "RdzvEvent"]
class EventSource(str, Enum):
"""Producer of an event: the agent process, a worker process, or the rendezvous layer."""
AGENT = "AGENT"
WORKER = "WORKER"
RDZV = "RDZV"
[docs]
class NodeState(str, Enum):
"""Lifecycle state carried by events."""
INITIALIZED = "INITIALIZED"
STARTING = "STARTING"
RUNNING = "RUNNING"
SUCCEEDED = "SUCCEEDED"
FAILED = "FAILED"
HEALTHY = "HEALTHY"
UNHEALTHY = "UNHEALTHY"
CLOSED = "CLOSED"
STOPPED = "STOPPED"
EventMetadataValue = Union[str, int, float, bool, None]
[docs]
@dataclass(init=False)
class Event:
"""A single agent or worker lifecycle event.
``event_type`` is a free-form string (typically a :class:`NodeState`
value) and ``metadata`` holds structured context such as rank ids.
"""
name: str
source: EventSource
timestamp: int
metadata: dict[str, EventMetadataValue]
def __init__(
self,
*args: Any,
name: str | None = None,
source: EventSource | str | None = None,
timestamp: int | None = None,
metadata: dict[str, EventMetadataValue] | None = None,
event_type: str | None = None,
created: int | None = None,
) -> None:
if args:
if isinstance(args[0], EventSource):
source = args[0]
if len(args) > 1:
event_type = args[1]
if len(args) > 2:
metadata = args[2]
if len(args) > 3:
created = args[3]
else:
name = args[0]
if len(args) > 1:
source = args[1]
if len(args) > 2:
timestamp = args[2]
if len(args) > 3:
metadata = args[3]
if source is None:
raise TypeError("source is required")
if isinstance(source, str):
source = EventSource[source] if source in EventSource.__members__ else EventSource(source)
self.name = name if name is not None else event_type or ""
self.source = source
self.timestamp = (
timestamp if timestamp is not None else created
if created is not None
else int(time.time() * 1000)
)
self.metadata = dict(metadata or {})
@property
def event_type(self) -> str:
return self.name
@event_type.setter
def event_type(self, value: str) -> None:
self.name = value
@property
def created(self) -> int:
return self.timestamp
@created.setter
def created(self, value: int) -> None:
self.timestamp = value
def __str__(self) -> str:
return self.serialize()
@staticmethod
def deserialize(data: str | "Event") -> "Event":
if isinstance(data, Event):
return data
payload = json.loads(data)
if "name" not in payload:
payload["name"] = payload.pop("event_type", "")
if "timestamp" not in payload:
payload["timestamp"] = payload.pop("created", 0)
source = payload.get("source")
if isinstance(source, str):
payload["source"] = (
EventSource[source]
if source in EventSource.__members__
else EventSource(source)
)
return Event(**payload)
def serialize(self) -> str:
return json.dumps(asdict(self))
[docs]
@dataclass(init=False)
class RdzvEvent:
"""A rendezvous progress event, rendered as JSON by the logging handler."""
name: str
run_id: str
message: str
hostname: str
pid: int
node_state: NodeState
master_endpoint: str
rank: int | None
local_id: int | None
error_trace: str
def __init__(
self,
*args: Any,
name: str | None = None,
run_id: str = "",
message: str = "",
hostname: str = "",
pid: int = 0,
node_state: NodeState | str = NodeState.RUNNING,
master_endpoint: str = "",
rank: int | None = None,
local_id: int | None = None,
error_trace: str = "",
rendezvous_id: str | None = None,
local_rank: int | None = None,
created: int | None = None,
) -> None:
if args:
names = [
"run_id", "message", "node_state", "hostname", "pid",
"master_endpoint", "rank", "local_rank", "rendezvous_id", "created",
]
values = dict(zip(names, args))
run_id = values.get("run_id", run_id)
message = values.get("message", message)
node_state = values.get("node_state", node_state)
hostname = values.get("hostname", hostname)
pid = values.get("pid", pid)
master_endpoint = values.get("master_endpoint", master_endpoint)
rank = values.get("rank", rank)
local_rank = values.get("local_rank", local_rank)
rendezvous_id = values.get("rendezvous_id", rendezvous_id)
created = values.get("created", created)
if isinstance(node_state, str):
node_state = (
NodeState[node_state]
if node_state in NodeState.__members__
else NodeState(node_state)
)
self.name = name if name is not None else rendezvous_id or ""
self.run_id = run_id
self.message = message
self.hostname = hostname
self.pid = int(pid)
self.node_state = node_state
self.master_endpoint = master_endpoint
self.rank = rank
self.local_id = local_id if local_id is not None else local_rank
self.error_trace = error_trace
self._created = (
created if created is not None else int(time.time() * 1000) // 1000
)
@property
def rendezvous_id(self) -> str:
return self.name
@rendezvous_id.setter
def rendezvous_id(self, value: str) -> None:
self.name = value
@property
def local_rank(self) -> int | None:
return self.local_id
@local_rank.setter
def local_rank(self, value: int | None) -> None:
self.local_id = value
@property
def created(self) -> int:
return self._created
@created.setter
def created(self, value: int) -> None:
self._created = value
def __str__(self) -> str:
return self.serialize()
@staticmethod
def deserialize(data: str | "RdzvEvent") -> "RdzvEvent":
if isinstance(data, RdzvEvent):
return data
payload = json.loads(data)
if "name" not in payload:
payload["name"] = payload.pop("rendezvous_id", "")
if "local_id" not in payload:
payload["local_id"] = payload.pop("local_rank", None)
payload.pop("created", None)
if "node_state" in payload and isinstance(payload["node_state"], str):
value = payload["node_state"]
payload["node_state"] = (
NodeState[value] if value in NodeState.__members__ else NodeState(value)
)
return RdzvEvent(**payload)
def serialize(self) -> str:
return json.dumps(asdict(self))Help improve this page
Found an error, an unclear step, or a missing example?
Was this page helpful?

