Notifications

pyNetX supports NETCONF notification subscriptions through subscribe_async(). Notifications are received on a separate SSH/NETCONF session from the primary RPC session.

Basic subscription

import asyncio
import pyNetX

async def main():
    client = pyNetX.NetconfClient(
        hostname="192.168.1.1",
        username="admin",
        password="admin",
        notif_queue_size=1000,
        label="leaf-01",
    )

    await client.connect_async()
    try:
        reply = await client.subscribe_async(stream="NETCONF")
        print("subscription reply:", reply)

        while client.is_subscription_active():
            notification = await client.next_notification_async(timeout_ms=1000)
            if notification:
                print(notification)
    finally:
        try:
            client.delete_subscription()
        finally:
            await client.disconnect_async()

asyncio.run(main())

Queue helpers

API

Description

client.next_notification(timeout_ms=10)

Synchronous queue read. Releases the Python GIL while waiting.

await client.next_notification_async(timeout_ms=10)

Awaitable queue read.

client.peek_notifications(max_items=100)

Inspect queued notifications without consuming them. Use -1 for all queued items.

client.notification_queue_size()

Return the current queue depth.

client.is_subscription_active()

Return whether the subscription is active.

client.delete_subscription()

Close the notification session/subscription. Safe to call during cleanup.

Bounded and unbounded queues

notif_queue_size=-1 creates an unbounded notification queue. This is the default.

A non-negative notif_queue_size creates a bounded queue. If the queue is full, pyNetX drops incoming notifications and emits health events such as notification_queue_full and notification_drops_summary.

Example bounded queue:

client = pyNetX.NetconfClient(
    hostname="192.168.1.1",
    username="admin",
    password="admin",
    notif_queue_size=1000,
    notif_drop_event_threshold=10,
    label="leaf-01",
)

Notification stream parser behavior

pyNetX v2.0.7 treats the notification SSH channel as a byte stream. A single reactor callback may receive multiple complete notifications, one complete notification plus part of the next one, only part of a notification, or malformed device data. The client keeps a persistent receive buffer for the active subscription and parses from that buffer.

Device stream case

Behavior

Health event

One complete notification ending in ]]>]]>

Queued with the EOM marker.

None

Multiple complete notifications in one read

Split and queued as separate notifications.

None

Complete notification followed by partial next notification

Complete notification is queued; trailing partial bytes stay in the receive buffer.

None immediately

Partial notification completed by a later read

Saved partial bytes are combined with later bytes and queued as one complete notification.

None

New <notification> starts before the previous one completed

Previous fragment is queued as an abandoned partial and parsing continues from the new start tag.

incomplete_notification

EOM-delimited data is not valid notification XML

Malformed frame is queued for inspection.

malformed_notification

Empty EOM-only frame

Empty frame is dropped.

malformed_notification

Orphan bytes before a notification start tag

Orphan prefix is dropped and parsing continues.

malformed_notification

Complete notification XML is followed by another notification without an EOM between them

First notification is recovered and queued without adding a synthetic EOM.

malformed_notification

Partial bytes never receive EOM before a guard fires

Partial bytes are queued without EOM.

incomplete_notification

For backward compatibility, valid EOM-delimited notifications returned by next_notification() and next_notification_async() still include the ]]>]]> marker. Partial and recovered missing-EOM fragments are returned as received, without adding a synthetic marker.

Incomplete notification guards

Some devices or broken test targets may send partial notification XML without the NETCONF ]]>]]> end marker. pyNetX has two guards:

  • notif_incomplete_max_kb: maximum partial notification size before a guard fires.

  • notif_incomplete_timeout: maximum seconds to wait for EOM after partial data starts.

At least one guard must remain enabled. Do not set both to -1.

When a guard fires, pyNetX emits an incomplete_notification health event and queues the partial bytes for inspection.