Skip to content

Conversation

@Llamrei
Copy link
Contributor

@Llamrei Llamrei commented Nov 30, 2025

Currently if you specify a max_rpm to an Agent, the program is unable to exit. To the user this looks like a program that never exits even after completion.

I think this is due to the Timer thread used to monitor the rate limiter inheriting Daemon behaviour from caller.

Proposed fix essentially says we always want to kill this specific timer if we exit no matter what and we make no effort to gracefully stop the timer. This solution seems reasonable for a timer that is simply a helper on rate limiting to external providers. No critical code (by definition) should be running while this thread is waiting.

Small reproducible example on my system, adapted from the docs:

from crewai.flow.flow import Flow, listen, start, router
from crewai.agent import Agent

import asyncio
from pydantic import BaseModel

class Result(BaseModel):
    fun_fact: str
    city: str

class FlowState(BaseModel):
    city: str = ""

class City(BaseModel):
    city: str

class ExampleFlow(Flow[FlowState]):
    model = "gpt-4o-mini"

    @start()
    async def generate_city(self):
        print("Starting flow")
        # Each flow state automatically gets a unique ID
        print(f"Flow State ID: {self.state.id}")
        simple_agent = Agent(
            role="Simple Agent",
            goal="Generate a random city name",
            backstory="You are a simple agent that generates a random city name.",
            llm="gpt-4o-mini",
            max_rpm=10,
        ) 

        result = await simple_agent.kickoff_async(
            "Generate a random city name.",
            response_format=City
        )   

        self.state.city = result.pydantic.city
    
    @router(generate_city)
    def check_if_london(self):
        if self.state.city == "London":
            return "generate_dull_fact"
        else:
            return "generate_fun_fact"

    @listen("generate_fun_fact")
    async def gen_fun(self):

        simple_agent = Agent(
            role="Simple Agent",
            goal="Generate a random city name",
            backstory="You are a simple agent that generates a random city name.",
            llm="gpt-4o-mini",
            verbose=False
        )
        response = await simple_agent.kickoff_async(
            f"Tell me a fun fact about {self.state.city}",
        )

        fun_fact = response.raw
        print("="*80)
        print(fun_fact)
        print("="*80)
        return Result(city=self.state.city, fun_fact=fun_fact)    

    @listen("generate_dull_fact")
    async def gen_dull(self):

        simple_agent = Agent(
            role="Simple Agent",
            goal="Generate a random city name",
            backstory="You are a simple agent that generates a random city name.",
            llm="gpt-4o-mini",
            verbose=False
        )
        response = await simple_agent.kickoff_async(
            f"Tell me a dull fact about {self.state.city}",

        )

        dull_fact = response.raw
        print("="*80)
        print(dull_fact)
        print("="*80)
        return Result(city=self.state.city, fun_fact=dull_fact)



# Usage example
async def run_flow(arg):
    print(arg)
    flow = ExampleFlow(tracing=False)
    result = await flow.kickoff_async(inputs={"file_path": arg})
    return result


# Run the flow
if __name__ == "__main__":
    result = asyncio.run(run_flow("sample_image.jpeg"))
    print(result)

On my system before the change this code hangs and never exits (after print result); after the change it works as expected.


Note

Marks the RPMController's reset timer as a daemon thread so processes can exit cleanly when max_rpm is set.

Written by Cursor Bugbot for commit 26a0597. This will update automatically on new commits. Configure here.

@greysonlalonde
Copy link
Contributor

@Llamrei thanks! will take a look

@greysonlalonde greysonlalonde changed the title RPMController hangs exit - 1 line fix fix: set rpm controller timer as daemon to prevent process hang Dec 11, 2025
@greysonlalonde
Copy link
Contributor

Cheers @Llamrei !

@greysonlalonde greysonlalonde merged commit 807f971 into crewAIInc:main Dec 11, 2025
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants