-
Notifications
You must be signed in to change notification settings - Fork 71
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
fix: catch all exceptions in forked process #921
fix: catch all exceptions in forked process #921
Conversation
Coverage reportClick to see where and how coverage changed
This report was generated by python-coverage-comment-action |
b00cc77
to
56c4f9e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything fine except for the queue size, not sure if the change for setting the max_size
to 1
can decrease the performances
# todo: This will leave residues on sys.path in case of exceptions. If really must | ||
# mutate sys.path, we should at least wrap in try-finally. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cannot we do as final action a tree delete marking the protobuf folder as the father folder to delete? In that way (unless the path of the dependencies contain ../../name
we can delete everything eventually)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know you didn't introduce the comment but can be solved in that way
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the protobuf files are ok to keep, if the one exists it will be reused and protoc
is not called.
The mangling of sys.path
and the lines below should be wrapped in try-except-else-finally
block to remove the added path if something fails. But not removed if it already was there.
karapace/protobuf/io.py
Outdated
@@ -233,34 +237,37 @@ def __init__( | |||
def read(self, bio: BytesIO) -> dict: | |||
if self._reader_schema is None: | |||
self._reader_schema = self._writer_schema | |||
return reader_mp(self.config, self._writer_schema, self._reader_schema, bio) | |||
return read_in_forked_process_multiprocess_process(self.config, self._writer_schema, self._reader_schema, bio) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good rename!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could remove the extra _process_
though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -168,25 +168,25 @@ def read_data( | |||
return class_instance | |||
|
|||
|
|||
_ReaderQueue: TypeAlias = "Queue[dict[object, object] | Exception]" | |||
_ReaderQueue: TypeAlias = "Queue[dict[object, object] | BaseException]" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
karapace/protobuf/io.py
Outdated
@@ -233,34 +237,37 @@ def __init__( | |||
def read(self, bio: BytesIO) -> dict: | |||
if self._reader_schema is None: | |||
self._reader_schema = self._writer_schema | |||
return reader_mp(self.config, self._writer_schema, self._reader_schema, bio) | |||
return read_in_forked_process_multiprocess_process(self.config, self._writer_schema, self._reader_schema, bio) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good rename!
@@ -274,14 +281,18 @@ def writer_mp( | |||
# To avoid problem with enum values for basic SerDe support we | |||
# will isolate work with call protobuf libraries in child process. | |||
if __name__ == "karapace.protobuf.io": | |||
queue: _WriterQueue = Queue() | |||
p = Process(target=writer_process, args=(queue, config, writer_schema, message_name, datum)) | |||
writer_queue: _WriterQueue = Queue(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why only 1 message in the queue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it make sense to proceed with just 1 at a time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is nothing else put to queue than one message at a time which the caller waits for. I decided just to make the size explicit here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
didn't notice wasn't reused and we have 1 process for each message
56c4f9e
to
c945648
Compare
If base exception is raised the communication queue will block in the calling process and will cause timeouts. This is prevalent in unit test for protobuf serialization in Github Actions, caused by the protobuf compiler work directory existence. The fix is to use pathlib.Path with exists=True and parents=True for removing the FileExistsError and also changing the error handling logic to pass back also BaseExceptions through the multiprocess queue.
c945648
to
8f0a350
Compare
If base exception is raised the communication queue will block in the calling process and will cause timeouts. This is prevalent in unit test for protobuf serialization in Github Actions, caused by the protobuf compiler work directory existence. The fix is to use pathlib.Path with exists=True and parents=True for removing the FileExistsError and also changing the error handling logic to pass back also BaseExceptions through the multiprocess queue.
About this change - What it does
References: #xxxxx
Why this way