Skip to content

Sync

The problem with fire-and-forget

All MQSC START and STOP commands are fire-and-forget — they return immediately without waiting for the object to reach its target state. In practice, tooling that provisions infrastructure needs to wait until a channel is RUNNING or a listener is STOPPED before proceeding to the next step. Writing polling loops by hand is error-prone and clutters business logic with retry mechanics.

The sync pattern

The *_sync and restart_* methods wrap the fire-and-forget commands with a polling loop that issues DISPLAY *STATUS until the object reaches a stable state or the timeout expires.

SyncOperation

An enum indicating the operation that was performed:

class SyncOperation(Enum):
    STARTED    = "started"     # Object confirmed running
    STOPPED    = "stopped"     # Object confirmed stopped
    RESTARTED  = "restarted"   # Stop-then-start completed

SyncConfig

Configuration controlling the polling behaviour:

@dataclass
class SyncConfig:
    timeout: float = 30.0         # Max seconds before raising
    poll_interval: float = 1.0    # Seconds between polls
Attribute Type Description
timeout float Maximum seconds to wait before raising MQRESTTimeoutError
poll_interval float Seconds between DISPLAY *STATUS polls

SyncResult

Contains the outcome of a sync operation:

class SyncResult(NamedTuple):
    operation: SyncOperation   # What happened
    polls: int                 # Number of status polls issued
    elapsed: float             # Wall-clock seconds from command to confirmation
Attribute Type Description
operation SyncOperation What happened: STARTED, STOPPED, or RESTARTED
polls int Number of status polls issued
elapsed float Wall-clock seconds from command to confirmation

Method signature pattern

All 9 sync methods follow the same signature pattern:

def start_channel_sync(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:

The config parameter is keyword-only for API clarity.

Basic usage

from pymqrest import SyncConfig, SyncOperation

# Start a channel and wait until it is RUNNING
result = session.start_channel_sync("TO.PARTNER")
assert result.operation is SyncOperation.STARTED
print(f"Channel running after {result.polls} poll(s), {result.elapsed:.1f}s")

# Stop a listener and wait until it is STOPPED
result = session.stop_listener_sync("TCP.LISTENER")
assert result.operation is SyncOperation.STOPPED

Custom timeout and poll interval

Pass a SyncConfig to override the defaults:

from pymqrest import SyncConfig

# Aggressive polling for fast local development
fast = SyncConfig(timeout_seconds=10.0, poll_interval_seconds=0.25)
result = session.start_service_sync("MY.SVC", config=fast)

# Patient polling for remote queue managers
patient = SyncConfig(timeout_seconds=120.0, poll_interval_seconds=5.0)
result = session.start_channel_sync("REMOTE.CHL", config=patient)

Restart convenience

The restart_* methods perform a synchronous stop followed by a synchronous start. Each phase gets the full timeout independently — worst case is 2x the configured timeout.

The returned SyncResult reports total polls and total elapsed time across both phases:

result = session.restart_channel("TO.PARTNER")
assert result.operation is SyncOperation.RESTARTED
print(f"Restarted in {result.elapsed:.1f}s ({result.polls} total polls)")

Timeout handling

When the timeout expires, MQRESTTimeoutError is raised with diagnostic attributes:

from pymqrest import MQRESTTimeoutError, SyncConfig

try:
    session.start_channel_sync(
        "BROKEN.CHL",
        config=SyncConfig(timeout_seconds=15.0),
    )
except MQRESTTimeoutError as err:
    print(f"Object: {err.name}")       # "BROKEN.CHL"
    print(f"Operation: {err.operation}")  # "start"
    print(f"Elapsed: {err.elapsed:.1f}s")  # 15.0

MQRESTTimeoutError inherits from MQRESTError, so existing except MQRESTError handlers will catch it.

Available methods

Method Operation START/STOP qualifier Status qualifier
start_channel_sync() Start CHANNEL CHSTATUS
stop_channel_sync() Stop CHANNEL CHSTATUS
restart_channel() Restart CHANNEL CHSTATUS
start_listener_sync() Start LISTENER LSSTATUS
stop_listener_sync() Stop LISTENER LSSTATUS
restart_listener() Restart LISTENER LSSTATUS
start_service_sync() Start SERVICE SVSTATUS
stop_service_sync() Stop SERVICE SVSTATUS
restart_service() Restart SERVICE SVSTATUS

Status detection

The polling loop checks the STATUS attribute in the DISPLAY *STATUS response. The target values are:

  • Start: RUNNING
  • Stop: STOPPED

Channel stop edge case

When a channel stops, its CHSTATUS record may disappear entirely (the DISPLAY CHSTATUS response returns no rows). The channel sync methods treat an empty status result as successfully stopped. Listener and service status records are always present, so empty results are not treated as stopped for those object types.

Attribute mapping

The sync methods call _mqsc_command internally, so they participate in the same mapping pipeline as all other command methods. The status key is checked using both the mapped snake_case name and the raw MQSC name, so polling works correctly regardless of whether mapping is enabled or disabled.

Provisioning example

The sync methods pair naturally with the ensure methods for end-to-end provisioning:

from pymqrest import SyncConfig

config = SyncConfig(timeout_seconds=60.0)

# Ensure listeners exist for application and admin traffic
session.ensure_listener("APP.LISTENER", request_parameters={
    "transport_type": "TCP",
    "port": 1415,
    "start_mode": "MQSVC_CONTROL_Q_MGR",
})
session.ensure_listener("ADMIN.LISTENER", request_parameters={
    "transport_type": "TCP",
    "port": 1416,
    "start_mode": "MQSVC_CONTROL_Q_MGR",
})

# Start them synchronously
session.start_listener_sync("APP.LISTENER", config=config)
session.start_listener_sync("ADMIN.LISTENER", config=config)

print("Listeners ready")

Rolling restart example

Restart all listeners with error handling — useful when a queue manager serves multiple TCP ports for different client populations:

from pymqrest import MQRESTTimeoutError, SyncConfig

listeners = ["APP.LISTENER", "ADMIN.LISTENER", "PARTNER.LISTENER"]
config = SyncConfig(timeout_seconds=30.0, poll_interval_seconds=2.0)

for name in listeners:
    try:
        result = session.restart_listener(name, config=config)
        print(f"{name}: restarted in {result.elapsed:.1f}s")
    except MQRESTTimeoutError as err:
        print(f"{name}: timed out after {err.elapsed:.1f}s")

API reference

Configuration for synchronous polling operations.

Attributes:

Name Type Description
timeout_seconds float

Maximum wall-clock seconds to wait for the object to reach the target state.

poll_interval_seconds float

Seconds to sleep between status polls.

Source code in src/pymqrest/sync.py
@dataclass(frozen=True)
class SyncConfig:
    """Configuration for synchronous polling operations.

    Attributes:
        timeout_seconds: Maximum wall-clock seconds to wait for the
            object to reach the target state.
        poll_interval_seconds: Seconds to sleep between status polls.

    """

    timeout_seconds: float = 30.0
    poll_interval_seconds: float = 1.0

    def __post_init__(self) -> None:
        """Validate that both fields are positive."""
        if self.timeout_seconds <= 0:
            msg = f"timeout_seconds must be positive, got {self.timeout_seconds}"
            raise ValueError(msg)
        if self.poll_interval_seconds <= 0:
            msg = f"poll_interval_seconds must be positive, got {self.poll_interval_seconds}"
            raise ValueError(msg)

timeout_seconds = 30.0 class-attribute instance-attribute

poll_interval_seconds = 1.0 class-attribute instance-attribute

__init__(timeout_seconds=30.0, poll_interval_seconds=1.0)

__post_init__()

Validate that both fields are positive.

Source code in src/pymqrest/sync.py
def __post_init__(self) -> None:
    """Validate that both fields are positive."""
    if self.timeout_seconds <= 0:
        msg = f"timeout_seconds must be positive, got {self.timeout_seconds}"
        raise ValueError(msg)
    if self.poll_interval_seconds <= 0:
        msg = f"poll_interval_seconds must be positive, got {self.poll_interval_seconds}"
        raise ValueError(msg)

Bases: Enum

Operation performed by a synchronous wrapper.

Attributes:

Name Type Description
STARTED

The object was started and confirmed running.

STOPPED

The object was stopped and confirmed stopped.

RESTARTED

The object was stopped then started.

Source code in src/pymqrest/sync.py
class SyncOperation(enum.Enum):
    """Operation performed by a synchronous wrapper.

    Attributes:
        STARTED: The object was started and confirmed running.
        STOPPED: The object was stopped and confirmed stopped.
        RESTARTED: The object was stopped then started.

    """

    STARTED = "started"
    STOPPED = "stopped"
    RESTARTED = "restarted"

STARTED = 'started' class-attribute instance-attribute

STOPPED = 'stopped' class-attribute instance-attribute

RESTARTED = 'restarted' class-attribute instance-attribute

Result of a synchronous start/stop/restart operation.

Attributes:

Name Type Description
operation SyncOperation

The :class:SyncOperation that was performed.

polls int

Total number of status polls issued.

elapsed_seconds float

Total wall-clock seconds from command to target state confirmation.

Source code in src/pymqrest/sync.py
@dataclass(frozen=True)
class SyncResult:
    """Result of a synchronous start/stop/restart operation.

    Attributes:
        operation: The :class:`SyncOperation` that was performed.
        polls: Total number of status polls issued.
        elapsed_seconds: Total wall-clock seconds from command to
            target state confirmation.

    """

    operation: SyncOperation
    polls: int
    elapsed_seconds: float

operation instance-attribute

polls instance-attribute

elapsed_seconds instance-attribute

__init__(operation, polls, elapsed_seconds)

Mixin providing synchronous start/stop/restart wrappers.

Each *_sync method issues the MQSC command then polls the corresponding DISPLAY *STATUS until the object reaches a stable state or the timeout expires. restart_* methods perform a synchronous stop followed by a synchronous start.

Source code in src/pymqrest/sync.py
class MQRESTSyncMixin:
    """Mixin providing synchronous start/stop/restart wrappers.

    Each ``*_sync`` method issues the MQSC command then polls the
    corresponding ``DISPLAY *STATUS`` until the object reaches a
    stable state or the timeout expires.  ``restart_*`` methods
    perform a synchronous stop followed by a synchronous start.
    """

    def _mqsc_command(
        self,
        *,
        command: str,
        mqsc_qualifier: str,
        name: str | None,
        request_parameters: Mapping[str, object] | None,
        response_parameters: Sequence[str] | None,
        where: str | None = None,
    ) -> list[dict[str, object]]:
        raise NotImplementedError  # pragma: no cover

    # ------------------------------------------------------------------
    # Channel
    # ------------------------------------------------------------------

    def start_channel_sync(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Start a channel and wait until it is running.

        Args:
            name: Channel name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with operation details.

        Raises:
            MQRESTTimeoutError: If the channel does not reach RUNNING
                within the timeout.

        """
        return self._start_and_poll(name, _CHANNEL_CONFIG, config)

    def stop_channel_sync(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Stop a channel and wait until it is stopped.

        Args:
            name: Channel name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with operation details.

        Raises:
            MQRESTTimeoutError: If the channel does not reach STOPPED
                within the timeout.

        """
        return self._stop_and_poll(name, _CHANNEL_CONFIG, config)

    def restart_channel(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Stop then start a channel, waiting for each phase.

        Each phase gets the full timeout independently.

        Args:
            name: Channel name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with total polls and elapsed time
            across both phases.

        Raises:
            MQRESTTimeoutError: If either phase exceeds the timeout.

        """
        return self._restart(name, _CHANNEL_CONFIG, config)

    # ------------------------------------------------------------------
    # Listener
    # ------------------------------------------------------------------

    def start_listener_sync(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Start a listener and wait until it is running.

        Args:
            name: Listener name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with operation details.

        Raises:
            MQRESTTimeoutError: If the listener does not reach RUNNING
                within the timeout.

        """
        return self._start_and_poll(name, _LISTENER_CONFIG, config)

    def stop_listener_sync(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Stop a listener and wait until it is stopped.

        Args:
            name: Listener name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with operation details.

        Raises:
            MQRESTTimeoutError: If the listener does not reach STOPPED
                within the timeout.

        """
        return self._stop_and_poll(name, _LISTENER_CONFIG, config)

    def restart_listener(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Stop then start a listener, waiting for each phase.

        Each phase gets the full timeout independently.

        Args:
            name: Listener name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with total polls and elapsed time
            across both phases.

        Raises:
            MQRESTTimeoutError: If either phase exceeds the timeout.

        """
        return self._restart(name, _LISTENER_CONFIG, config)

    # ------------------------------------------------------------------
    # Service
    # ------------------------------------------------------------------

    def start_service_sync(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Start a service and wait until it is running.

        Args:
            name: Service name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with operation details.

        Raises:
            MQRESTTimeoutError: If the service does not reach RUNNING
                within the timeout.

        """
        return self._start_and_poll(name, _SERVICE_CONFIG, config)

    def stop_service_sync(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Stop a service and wait until it is stopped.

        Args:
            name: Service name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with operation details.

        Raises:
            MQRESTTimeoutError: If the service does not reach STOPPED
                within the timeout.

        """
        return self._stop_and_poll(name, _SERVICE_CONFIG, config)

    def restart_service(
        self,
        name: str,
        *,
        config: SyncConfig | None = None,
    ) -> SyncResult:
        """Stop then start a service, waiting for each phase.

        Each phase gets the full timeout independently.

        Args:
            name: Service name.
            config: Optional polling configuration.

        Returns:
            A :class:`SyncResult` with total polls and elapsed time
            across both phases.

        Raises:
            MQRESTTimeoutError: If either phase exceeds the timeout.

        """
        return self._restart(name, _SERVICE_CONFIG, config)

    # ------------------------------------------------------------------
    # Core polling helpers
    # ------------------------------------------------------------------

    def _start_and_poll(
        self,
        name: str,
        object_config: _ObjectTypeConfig,
        config: SyncConfig | None,
    ) -> SyncResult:
        """Issue START then poll until the object is RUNNING."""
        sync_config = config or SyncConfig()
        self._mqsc_command(
            command="START",
            mqsc_qualifier=object_config.start_qualifier,
            name=name,
            request_parameters=None,
            response_parameters=None,
        )
        polls = 0
        start_time = time.monotonic()
        while True:
            time.sleep(sync_config.poll_interval_seconds)
            status_rows = self._mqsc_command(
                command="DISPLAY",
                mqsc_qualifier=object_config.status_qualifier,
                name=name,
                request_parameters=None,
                response_parameters=["all"],
            )
            polls += 1
            if _has_status(status_rows, object_config.status_keys, _RUNNING_VALUES):
                elapsed = time.monotonic() - start_time
                return SyncResult(SyncOperation.STARTED, polls=polls, elapsed_seconds=elapsed)
            elapsed = time.monotonic() - start_time
            if elapsed >= sync_config.timeout_seconds:
                message = f"{object_config.start_qualifier} '{name}' did not reach RUNNING within {sync_config.timeout_seconds}s"
                raise MQRESTTimeoutError(
                    message,
                    name=name,
                    operation="start",
                    elapsed=elapsed,
                )

    def _stop_and_poll(
        self,
        name: str,
        object_config: _ObjectTypeConfig,
        config: SyncConfig | None,
    ) -> SyncResult:
        """Issue STOP then poll until the object is STOPPED."""
        sync_config = config or SyncConfig()
        self._mqsc_command(
            command="STOP",
            mqsc_qualifier=object_config.stop_qualifier,
            name=name,
            request_parameters=None,
            response_parameters=None,
        )
        polls = 0
        start_time = time.monotonic()
        while True:
            time.sleep(sync_config.poll_interval_seconds)
            status_rows = self._mqsc_command(
                command="DISPLAY",
                mqsc_qualifier=object_config.status_qualifier,
                name=name,
                request_parameters=None,
                response_parameters=["all"],
            )
            polls += 1
            if object_config.empty_means_stopped and not status_rows:
                elapsed = time.monotonic() - start_time
                return SyncResult(SyncOperation.STOPPED, polls=polls, elapsed_seconds=elapsed)
            if _has_status(status_rows, object_config.status_keys, _STOPPED_VALUES):
                elapsed = time.monotonic() - start_time
                return SyncResult(SyncOperation.STOPPED, polls=polls, elapsed_seconds=elapsed)
            elapsed = time.monotonic() - start_time
            if elapsed >= sync_config.timeout_seconds:
                message = f"{object_config.stop_qualifier} '{name}' did not reach STOPPED within {sync_config.timeout_seconds}s"
                raise MQRESTTimeoutError(
                    message,
                    name=name,
                    operation="stop",
                    elapsed=elapsed,
                )

    def _restart(
        self,
        name: str,
        object_config: _ObjectTypeConfig,
        config: SyncConfig | None,
    ) -> SyncResult:
        """Stop-sync then start-sync, returning combined totals."""
        stop_result = self._stop_and_poll(name, object_config, config)
        start_result = self._start_and_poll(name, object_config, config)
        return SyncResult(
            SyncOperation.RESTARTED,
            polls=stop_result.polls + start_result.polls,
            elapsed_seconds=stop_result.elapsed_seconds + start_result.elapsed_seconds,
        )

_mqsc_command(*, command, mqsc_qualifier, name, request_parameters, response_parameters, where=None)

Source code in src/pymqrest/sync.py
def _mqsc_command(
    self,
    *,
    command: str,
    mqsc_qualifier: str,
    name: str | None,
    request_parameters: Mapping[str, object] | None,
    response_parameters: Sequence[str] | None,
    where: str | None = None,
) -> list[dict[str, object]]:
    raise NotImplementedError  # pragma: no cover

start_channel_sync(name, *, config=None)

Start a channel and wait until it is running.

Parameters:

Name Type Description Default
name str

Channel name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with operation details.

Raises:

Type Description
MQRESTTimeoutError

If the channel does not reach RUNNING within the timeout.

Source code in src/pymqrest/sync.py
def start_channel_sync(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Start a channel and wait until it is running.

    Args:
        name: Channel name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with operation details.

    Raises:
        MQRESTTimeoutError: If the channel does not reach RUNNING
            within the timeout.

    """
    return self._start_and_poll(name, _CHANNEL_CONFIG, config)

stop_channel_sync(name, *, config=None)

Stop a channel and wait until it is stopped.

Parameters:

Name Type Description Default
name str

Channel name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with operation details.

Raises:

Type Description
MQRESTTimeoutError

If the channel does not reach STOPPED within the timeout.

Source code in src/pymqrest/sync.py
def stop_channel_sync(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Stop a channel and wait until it is stopped.

    Args:
        name: Channel name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with operation details.

    Raises:
        MQRESTTimeoutError: If the channel does not reach STOPPED
            within the timeout.

    """
    return self._stop_and_poll(name, _CHANNEL_CONFIG, config)

restart_channel(name, *, config=None)

Stop then start a channel, waiting for each phase.

Each phase gets the full timeout independently.

Parameters:

Name Type Description Default
name str

Channel name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with total polls and elapsed time

SyncResult

across both phases.

Raises:

Type Description
MQRESTTimeoutError

If either phase exceeds the timeout.

Source code in src/pymqrest/sync.py
def restart_channel(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Stop then start a channel, waiting for each phase.

    Each phase gets the full timeout independently.

    Args:
        name: Channel name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with total polls and elapsed time
        across both phases.

    Raises:
        MQRESTTimeoutError: If either phase exceeds the timeout.

    """
    return self._restart(name, _CHANNEL_CONFIG, config)

start_listener_sync(name, *, config=None)

Start a listener and wait until it is running.

Parameters:

Name Type Description Default
name str

Listener name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with operation details.

Raises:

Type Description
MQRESTTimeoutError

If the listener does not reach RUNNING within the timeout.

Source code in src/pymqrest/sync.py
def start_listener_sync(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Start a listener and wait until it is running.

    Args:
        name: Listener name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with operation details.

    Raises:
        MQRESTTimeoutError: If the listener does not reach RUNNING
            within the timeout.

    """
    return self._start_and_poll(name, _LISTENER_CONFIG, config)

stop_listener_sync(name, *, config=None)

Stop a listener and wait until it is stopped.

Parameters:

Name Type Description Default
name str

Listener name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with operation details.

Raises:

Type Description
MQRESTTimeoutError

If the listener does not reach STOPPED within the timeout.

Source code in src/pymqrest/sync.py
def stop_listener_sync(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Stop a listener and wait until it is stopped.

    Args:
        name: Listener name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with operation details.

    Raises:
        MQRESTTimeoutError: If the listener does not reach STOPPED
            within the timeout.

    """
    return self._stop_and_poll(name, _LISTENER_CONFIG, config)

restart_listener(name, *, config=None)

Stop then start a listener, waiting for each phase.

Each phase gets the full timeout independently.

Parameters:

Name Type Description Default
name str

Listener name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with total polls and elapsed time

SyncResult

across both phases.

Raises:

Type Description
MQRESTTimeoutError

If either phase exceeds the timeout.

Source code in src/pymqrest/sync.py
def restart_listener(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Stop then start a listener, waiting for each phase.

    Each phase gets the full timeout independently.

    Args:
        name: Listener name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with total polls and elapsed time
        across both phases.

    Raises:
        MQRESTTimeoutError: If either phase exceeds the timeout.

    """
    return self._restart(name, _LISTENER_CONFIG, config)

start_service_sync(name, *, config=None)

Start a service and wait until it is running.

Parameters:

Name Type Description Default
name str

Service name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with operation details.

Raises:

Type Description
MQRESTTimeoutError

If the service does not reach RUNNING within the timeout.

Source code in src/pymqrest/sync.py
def start_service_sync(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Start a service and wait until it is running.

    Args:
        name: Service name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with operation details.

    Raises:
        MQRESTTimeoutError: If the service does not reach RUNNING
            within the timeout.

    """
    return self._start_and_poll(name, _SERVICE_CONFIG, config)

stop_service_sync(name, *, config=None)

Stop a service and wait until it is stopped.

Parameters:

Name Type Description Default
name str

Service name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with operation details.

Raises:

Type Description
MQRESTTimeoutError

If the service does not reach STOPPED within the timeout.

Source code in src/pymqrest/sync.py
def stop_service_sync(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Stop a service and wait until it is stopped.

    Args:
        name: Service name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with operation details.

    Raises:
        MQRESTTimeoutError: If the service does not reach STOPPED
            within the timeout.

    """
    return self._stop_and_poll(name, _SERVICE_CONFIG, config)

restart_service(name, *, config=None)

Stop then start a service, waiting for each phase.

Each phase gets the full timeout independently.

Parameters:

Name Type Description Default
name str

Service name.

required
config SyncConfig | None

Optional polling configuration.

None

Returns:

Name Type Description
A SyncResult

class:SyncResult with total polls and elapsed time

SyncResult

across both phases.

Raises:

Type Description
MQRESTTimeoutError

If either phase exceeds the timeout.

Source code in src/pymqrest/sync.py
def restart_service(
    self,
    name: str,
    *,
    config: SyncConfig | None = None,
) -> SyncResult:
    """Stop then start a service, waiting for each phase.

    Each phase gets the full timeout independently.

    Args:
        name: Service name.
        config: Optional polling configuration.

    Returns:
        A :class:`SyncResult` with total polls and elapsed time
        across both phases.

    Raises:
        MQRESTTimeoutError: If either phase exceeds the timeout.

    """
    return self._restart(name, _SERVICE_CONFIG, config)

_start_and_poll(name, object_config, config)

Issue START then poll until the object is RUNNING.

Source code in src/pymqrest/sync.py
def _start_and_poll(
    self,
    name: str,
    object_config: _ObjectTypeConfig,
    config: SyncConfig | None,
) -> SyncResult:
    """Issue START then poll until the object is RUNNING."""
    sync_config = config or SyncConfig()
    self._mqsc_command(
        command="START",
        mqsc_qualifier=object_config.start_qualifier,
        name=name,
        request_parameters=None,
        response_parameters=None,
    )
    polls = 0
    start_time = time.monotonic()
    while True:
        time.sleep(sync_config.poll_interval_seconds)
        status_rows = self._mqsc_command(
            command="DISPLAY",
            mqsc_qualifier=object_config.status_qualifier,
            name=name,
            request_parameters=None,
            response_parameters=["all"],
        )
        polls += 1
        if _has_status(status_rows, object_config.status_keys, _RUNNING_VALUES):
            elapsed = time.monotonic() - start_time
            return SyncResult(SyncOperation.STARTED, polls=polls, elapsed_seconds=elapsed)
        elapsed = time.monotonic() - start_time
        if elapsed >= sync_config.timeout_seconds:
            message = f"{object_config.start_qualifier} '{name}' did not reach RUNNING within {sync_config.timeout_seconds}s"
            raise MQRESTTimeoutError(
                message,
                name=name,
                operation="start",
                elapsed=elapsed,
            )

_stop_and_poll(name, object_config, config)

Issue STOP then poll until the object is STOPPED.

Source code in src/pymqrest/sync.py
def _stop_and_poll(
    self,
    name: str,
    object_config: _ObjectTypeConfig,
    config: SyncConfig | None,
) -> SyncResult:
    """Issue STOP then poll until the object is STOPPED."""
    sync_config = config or SyncConfig()
    self._mqsc_command(
        command="STOP",
        mqsc_qualifier=object_config.stop_qualifier,
        name=name,
        request_parameters=None,
        response_parameters=None,
    )
    polls = 0
    start_time = time.monotonic()
    while True:
        time.sleep(sync_config.poll_interval_seconds)
        status_rows = self._mqsc_command(
            command="DISPLAY",
            mqsc_qualifier=object_config.status_qualifier,
            name=name,
            request_parameters=None,
            response_parameters=["all"],
        )
        polls += 1
        if object_config.empty_means_stopped and not status_rows:
            elapsed = time.monotonic() - start_time
            return SyncResult(SyncOperation.STOPPED, polls=polls, elapsed_seconds=elapsed)
        if _has_status(status_rows, object_config.status_keys, _STOPPED_VALUES):
            elapsed = time.monotonic() - start_time
            return SyncResult(SyncOperation.STOPPED, polls=polls, elapsed_seconds=elapsed)
        elapsed = time.monotonic() - start_time
        if elapsed >= sync_config.timeout_seconds:
            message = f"{object_config.stop_qualifier} '{name}' did not reach STOPPED within {sync_config.timeout_seconds}s"
            raise MQRESTTimeoutError(
                message,
                name=name,
                operation="stop",
                elapsed=elapsed,
            )

_restart(name, object_config, config)

Stop-sync then start-sync, returning combined totals.

Source code in src/pymqrest/sync.py
def _restart(
    self,
    name: str,
    object_config: _ObjectTypeConfig,
    config: SyncConfig | None,
) -> SyncResult:
    """Stop-sync then start-sync, returning combined totals."""
    stop_result = self._stop_and_poll(name, object_config, config)
    start_result = self._start_and_poll(name, object_config, config)
    return SyncResult(
        SyncOperation.RESTARTED,
        polls=stop_result.polls + start_result.polls,
        elapsed_seconds=stop_result.elapsed_seconds + start_result.elapsed_seconds,
    )