how to handle custom cleanup actions in livekit ag...
# ask-ai
f
how to handle custom cleanup actions in livekit agents python lib for outbound sip call when the user doesn't answer or declines the call
t
Thanks for reaching out, Amjad. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
When you’re working with the LiveKit Python library for outbound SIP calls and want to handle situations where the user doesn’t answer or declines, here are some friendly tips to help you manage custom cleanup actions: • Keep an Eye on Call Status: You can use the
create_sip_participant
method with
wait_until_answered=True
to pause until the call is either answered or fails. Wrapping this in a `try`/`except` block lets you catch errors and log SIP status codes and messages — super handy for troubleshooting. • Create Custom Cleanup Functions: Think about adding a helper like
hangup()
to gracefully end calls by deleting the room. Here’s a quick example:
Copy code
async def hangup(self):
    await job_ctx.api.room.delete_room(
        api.DeleteRoomRequest(
            room=job_ctx.room.name,
        )
    )
Detect Voicemail: If you can spot when the call hits voicemail, you can trigger cleanup actions like hanging up right away to keep things tidy. • Handle Timeouts: Setting up timeouts for inactivity is a smart move — you can then run cleanup tasks to close sessions and delete rooms if no one picks up. • Clean Up Sessions Properly: Don’t forget to close API connections and free up resources in a
cleanup()
method to keep everything running smoothly. These steps should help you cover all your bases when calls go unanswered or get declined. If you want me to walk you through any part or give you more examples, just let me know — I’m here to help!
f
how to specify custom hangup / cleanup function that is executed every time - user doesn't answer, hangs up, the call ends normally.
t
Hey there! If you want to set up a custom hangup or cleanup function that runs no matter how the call ends (whether it’s no answer, the user hangs up, or the call finishes normally), here are some friendly ways to do it: • Shutdown Callbacks: You can use
ctx.add_shutdown_callback()
to register a cleanup function that kicks in whenever the session ends for any reason. Here’s a quick example:
Copy code
async def entrypoint(ctx: JobContext):
    async def my_shutdown_hook():
        <http://logger.info|logger.info>("Performing cleanup tasks")
        # Your cleanup code here
    ctx.add_shutdown_callback(my_shutdown_hook)
Session Close Event: Another way is to listen for the session’s
on("close")
event and handle cleanup when the session wraps up. Like this:
Copy code
@session.on("close")
def on_close(ev: CloseEvent):
    <http://logger.info|logger.info>(f"Session closed, reason: {ev.reason}")
    # Perform cleanup here
Agent
on_exit
Method:
You can also define an
on_exit
method inside your Agent class to tidy things up when the agent session ends. • Call Status Monitoring: Keep an eye on the
sip.callStatus
attribute to catch different end scenarios like user hangup or timeout. • Reusable Hangup Function: Consider making a handy helper function like
hangup_call()
that deletes the room and ends the call for everyone involved. Using these approaches will help make sure your cleanup runs smoothly no matter how the call ends. If you want me to walk you through any of these with more details or examples, just let me know—I’m here to help!
f
shutdown callback is not being called every time
t
Hey there! If your shutdown callback isn’t being called every time, no worries—here are some common reasons why that might happen and how you can fix them: • Forceful Termination: If the process gets killed abruptly with
SIGKILL
or something similar, the shutdown callbacks won’t get a chance to run. Try to make sure your process shuts down gracefully. • Timeout Exceeded: Shutdown hooks need to finish within the default 60-second timeout. If your callback is taking longer, you can bump up the timeout by adjusting the
shutdown_process_timeout
parameter in
WorkerOptions
. • Unhandled Exceptions: It’s a good idea to wrap your shutdown logic in `try`/`except` blocks. This way, if something goes wrong, it won’t stop other callbacks from running:
Copy code
async def my_shutdown_hook():
    try:
        # Your cleanup code here
    except Exception as e:
        logger.error(f"Shutdown hook failed: {e}")
Improper Session Termination: Make sure you’re calling
ctx.connect()
or
ctx.shutdown()
in your job’s entrypoint to properly manage the session lifecycle. • Register Callbacks Early: Add your shutdown callbacks right at the start of your entrypoint function so they’re set up before any long-running tasks begin. Hopefully, these tips help your shutdown callbacks run smoothly every time. If you hit any bumps or want to chat more about this, just let me know—I’m here to help! Sources: chain-of-thought-tts/agent.py | examples/voice_agents/realtime_joke_teller.py | Inside a session | LiveKit Docs | Job lifecycle | LiveKit Docs