JNB Global not seen outside of awaitio loop using ZMQ

I want to access the global variable most_recent_message anywhere in the notebook but it’s not working. The cell just is active (*) but nothing shows up. The messages are coming into the loop and they are printing out as expected so zmq is working but not the global. When I enter most_recent_message into any cell nothing happens. My expectation is that I should be able to type most tab and have it expand but that doesn’t work. It’s as if all the cells in the notebook are locked out.

Can anyone help me out please? this is my first time using zmq in a cell of a notebook to feed the rest of the cells

import zmq.asyncio
import asyncio
from IPython.display import clear_output
import nest_asyncio  # To allow nested asyncio loops in Jupyter

# Initialize zmq with asyncio
context = zmq.asyncio.Context()
socket = context.socket(zmq.SUB)
socket.bind("tcp://*:5555")
socket.setsockopt_string(zmq.SUBSCRIBE, "")

# Global variable to store the most recent message
most_recent_message = None

async def subscriber():
    """
    Asynchronous function to receive messages from ZeroMQ and update the global variable.
    """
    global most_recent_message
    print("Subscriber started. Waiting for messages...")
    while True:
        msg = await socket.recv_string()
        most_recent_message = msg  # Update the most recent message
        print(f"Received message: {most_recent_message}")  # Debug: Show received message

# Run the subscriber asynchronously in the background
loop = asyncio.get_event_loop()
task = loop.create_task(subscriber())

# Variable to store the last processed message
last_processed_message = None

def check_for_new_message():
    """
    Function to check if a new message has been received.
    """
    global last_processed_message
    print("check for new message", most_recent_message, "  ", last_processed_message) 
    if most_recent_message != last_processed_message:
        last_processed_message = most_recent_message
        return most_recent_message
    return None

def example_usage():
    """
    Example function to demonstrate how to check for new messages.
    """
    print("example usage")
    
    new_message = check_for_new_message()
    if new_message:
        print(f"New message received: {new_message}")
    else:
        print("No new messages.")

async def monitor_example_usage(interval=2):
    """
    Continuously monitors the output of example_usage() asynchronously.
    
    Parameters:
    - interval (int): Time in seconds between each check.
    """
    try:
        while True:
            clear_output(wait=True)  # Clear previous output
            example_usage()  # Call the function to check for new messages
            print("latest  ", most_recent_message)
            await asyncio.sleep(interval)  # Asynchronous sleep
    except KeyboardInterrupt:
        print("Monitoring stopped.")

# Allow nested asyncio loops in Jupyter Notebook
nest_asyncio.apply()

async def main():
    task_sub = asyncio.create_task(subscriber())
    await monitor_example_usage()

await main()

here is the PUB code I am using

# data_feed_1.py
import zmq
import time
import random

def main():
    context = zmq.Context()
    socket = context.socket(zmq.PUB)
    socket.connect("tcp://localhost:5555")  # Connect to subscriber's endpoint

    while True:
        message = f"Feed 1: Data {random.randint(1, 100)}"
        socket.send_string(message)
        print(f"Sent: {message}")
        time.sleep(random.uniform(0.5, 2))  # Send data at random intervals

if __name__ == "__main__":
    main()