Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/7694 executor cleanup #7765

Closed
wants to merge 59 commits into from
Closed

Conversation

Hugo-Inmanta
Copy link
Contributor

@Hugo-Inmanta Hugo-Inmanta commented Jun 24, 2024

Description

Closes #7694

Add 2 config options:

  • executor_retention: executors idle for longer than this get cleaned up
  • executor_cap_per_agent: if this limit is already reached when attempting to create a new executor for this agent, the oldest executor is first stopped.

Self Check:

Strike through any lines that are not applicable (~~line~~) then check the box

  • Attached issue to pull request
  • Changelog entry
  • Type annotations are present
  • Code is clear and sufficiently documented
  • No (preventable) type errors (check using make mypy or make mypy-diff)
  • Sufficient test cases (reproduces the bug/tests the requested feature)
  • Correct, in line with design
    - [ ] End user documentation is included or an issue is created for end-user documentation (add ref to issue here: )
    - [ ] If this PR fixes a race condition in the test suite, also push the fix to the relevant stable branche(s) (see test-fixes for more info)

@Hugo-Inmanta Hugo-Inmanta requested a review from wouterdb June 25, 2024 13:02
src/inmanta/agent/agent.py Outdated Show resolved Hide resolved
src/inmanta/agent/agent.py Outdated Show resolved Hide resolved
@Hugo-Inmanta Hugo-Inmanta requested review from wouterdb and sanderr June 26, 2024 08:39
src/inmanta/agent/forking_executor.py Outdated Show resolved Hide resolved
src/inmanta/agent/forking_executor.py Show resolved Hide resolved
src/inmanta/agent/config.py Outdated Show resolved Hide resolved
src/inmanta/data/__init__.py Outdated Show resolved Hide resolved
@Hugo-Inmanta Hugo-Inmanta requested a review from wouterdb June 26, 2024 12:54
@Hugo-Inmanta Hugo-Inmanta requested a review from wouterdb July 3, 2024 06:48
@@ -188,7 +189,7 @@ def is_executor_mode(value: str | AgentExecutorMode) -> AgentExecutorMode:
3,
"Maximum number of concurrent executors to keep per environment, per agent. If this limit is already reached "
"when creating a new executor, the oldest one will be stopped first.",
is_int,
functools.partial(is_lower_bounded_int, 1),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use the docstring of the function to generate documentation, so this won't look so pretty in the docs


self.stopping: bool = False
# We keep a reference to the periodic cleanup task to prevent it
# from disappearing mid-execution https://docs.python.org/3.11/library/asyncio-task.html#creating-tasks
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, nice!

return p, parent_conn

async def start(self) -> None:
self.cleanup_job = asyncio.create_task(self.cleanup_inactive_executors())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the join method, you could await self.cleanup_job to make sure it is down.

src/inmanta/config.py Outdated Show resolved Hide resolved
self.executor_retention_time = inmanta.agent.config.agent_executor_retention_time.get()
self.max_executors_per_agent = inmanta.agent.config.agent_executor_cap.get()

self.stopping: bool = False
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've already given more comment than I'm comfortable, so feel free to ignore this one: when used like this, I usually call this 'running' (and invert it) to make sure it doesn't only indicate 'stopping' but also 'stopped'

Comment on lines +89 to +90
# Clean up executors after 3s of inactivity
inmanta.agent.config.agent_executor_retention_time.set("3")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Increased this a bit because it was causing intempestive cleanup in the test case: the old executor is supposed to get cleaned up when the agent cap is reached, but with this setting too low, it would automatically get cleaned up before then.

@Hugo-Inmanta Hugo-Inmanta requested a review from wouterdb July 3, 2024 09:01
@@ -397,7 +399,21 @@ async def serve() -> None:
exit(0)


class MPExecutor(executor.Executor):
class PoolMember(abc.ABC):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Could use a docstring though.

@@ -518,7 +537,24 @@ async def get_facts(self, resource: "inmanta.agent.executor.ResourceDetails") ->
return await self.connection.call(FactsCommand(resource))


class MPManager(executor.ExecutorManager[MPExecutor]):
class PoolManager:
def __init__(self, max_time: int, max_pool_size: int, min_pool_size: int):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def __init__(self, max_time: int, max_pool_size: int, min_pool_size: int):
def __init__(self, *, max_time: int, max_pool_size: int, min_pool_size: int):

@@ -518,7 +537,24 @@ async def get_facts(self, resource: "inmanta.agent.executor.ResourceDetails") ->
return await self.connection.call(FactsCommand(resource))


class MPManager(executor.ExecutorManager[MPExecutor]):
class PoolManager:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class PoolManager:
class PoolManager(abc.ABC):

@@ -518,7 +537,24 @@ async def get_facts(self, resource: "inmanta.agent.executor.ResourceDetails") ->
return await self.connection.call(FactsCommand(resource))


class MPManager(executor.ExecutorManager[MPExecutor]):
class PoolManager:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest, I don't see the benefit of this class, or even the PoolMember class, the way they're implemented now. Sure, they present a common interface, but it doesn't seem like we use the interface in any meaningful way?

  • the get_pool_members method is not used
  • neither class offers any funcionality, meaning the cleanup methods are still custom

Am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, this is not useful right now, I'll remove it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not entirely what I'm trying to say. I think the concept is very good, if it allows us to share behavior between both use cases. So when @wouterdb proposed it, I'm assuming that's what he had in mind? By removing it, we're back to square one, aren't we?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll leave them out for now, see discussion on slack. I think it was intended for @hlloreda to factor out if necessary all along

@Hugo-Inmanta Hugo-Inmanta requested a review from sanderr July 3, 2024 11:53
Copy link
Contributor

@sanderr sanderr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My review is blocked on Wouter's response to this discussion.

@Hugo-Inmanta Hugo-Inmanta requested a review from sanderr July 3, 2024 12:19
@Hugo-Inmanta Hugo-Inmanta added the merge-tool-ready This ticket is ready to be merged in label Jul 3, 2024
@inmantaci
Copy link
Contributor

Processing this pull request

@inmantaci
Copy link
Contributor

Merged into branches master in 04983c4

@inmantaci inmantaci closed this Jul 3, 2024
inmantaci pushed a commit that referenced this pull request Jul 3, 2024
# Description

Closes #7694

Add 2 config options:
- `executor_retention`: executors idle for longer than this get cleaned up
- `executor_cap_per_agent`: if this limit is already reached when attempting to create a new executor for this agent, the oldest executor is first stopped.

# Self Check:

Strike through any lines that are not applicable (`~~line~~`) then check the box

- [x] Attached issue to pull request
- [x] Changelog entry
- [x] Type annotations are present
- [x] Code is clear and sufficiently documented
- [x] No (preventable) type errors (check using make mypy or make mypy-diff)
- [x] Sufficient test cases (reproduces the bug/tests the requested feature)
- [x] Correct, in line with design
~~- [ ] End user documentation is included or an issue is created for end-user documentation (add ref to issue here: )~~
~~- [ ] If this PR fixes a race condition in the test suite, also push the fix to the relevant stable branche(s) (see [test-fixes](https://internal.inmanta.com/development/core/tasks/build-master.html#test-fixes) for more info)~~
@inmantaci inmantaci deleted the issue/7694-executor-cleanup branch July 3, 2024 12:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge-tool-ready This ticket is ready to be merged in
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Executor Cleanup
4 participants