Skip to content

Commit

Permalink
add workaround for a multi thread issue of ruamel.yaml (#200)
Browse files Browse the repository at this point in the history
* use safe ruamel.yaml instance

Signed-off-by: hirokuni-kitahara <[email protected]>

* add retrying to yaml.dump

Signed-off-by: hirokuni-kitahara <[email protected]>

---------

Signed-off-by: hirokuni-kitahara <[email protected]>
  • Loading branch information
hirokuni-kitahara authored Oct 24, 2023
1 parent 58bce76 commit de41a4b
Showing 1 changed file with 29 additions and 7 deletions.
36 changes: 29 additions & 7 deletions ansible_risk_insight/yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
import io
from contextvars import ContextVar
from ruamel.yaml import YAML
from ruamel.yaml.emitter import EmitterError


_yaml: ContextVar[YAML] = ContextVar("yaml")


def _set_yaml():
if not _yaml.get(None):
yaml = YAML(typ="rt", pure=True)
def _set_yaml(force=False):
if not _yaml.get(None) or force:
yaml = YAML(typ="safe", pure=True)
yaml.default_flow_style = False
yaml.preserve_quotes = True
yaml.allow_duplicate_keys = True
Expand Down Expand Up @@ -53,9 +54,30 @@ def load(stream: any):
return yaml.load(stream)


# `ruamel.yaml` has a bug around multi-threading, and its YAML() instance could be broken
# while concurrent dump() operation. So we try retrying if the specific error occurs.
# Bug details: https://sourceforge.net/p/ruamel-yaml/tickets/367/
def dump(data: any):
_set_yaml()
yaml = _yaml.get()
output = io.StringIO()
yaml.dump(data, output)
return output.getvalue()
retry = 2
err = None
result = None
for i in range(retry):
try:
yaml = _yaml.get()
output = io.StringIO()
yaml.dump(data, output)
result = output.getvalue()
except EmitterError as exc:
err = exc
except Exception:
raise
if err:
if i < retry - 1:
_set_yaml(force=True)
err = None
else:
raise err
else:
break
return result

0 comments on commit de41a4b

Please sign in to comment.