-
Notifications
You must be signed in to change notification settings - Fork 96
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
RuntimeError after upgrading from 1.2.2 #244
Comments
I've just released 1.3.0, can you try with that? |
TBH I tried checking out 1.2.4 on Ubuntu 18.04, ran the code snippet you gave [simplification from the docs], and I couldn't replicate the error. Asciinema Recording: https://asciinema.org/a/Fih5rZOm5QGlIboe4JWysSdSX |
Update: I've just spun up a CentOS 7 instance, installed python3, created a new virtualenv, and also cannot replicate the error. Asciinema Recording: https://asciinema.org/a/6k5vSAI4lX5oyOn2OiwRYZNdM |
Thank you for the quick reply! I tried 1.3.0 but the problem remains:
I tried it on another Red Hat 7.9 server and there the same code works. Is there any way how I can find out what exactly is failing? |
Oookay, that's ... strange.
The lines that raised that exception are these lines. It's very hard to reach that line, as can be seen in the amount of acrobatics I have to do in the relevant test. Because even if the But I wonder ... Can you try this: from aiosmtpd.controller import Controller
from aiosmtpd.handlers import Sink
cont = Controller(Sink())
s1 = cont.factory()
print(repr(s1))
print(s1.hostname) |
Ok I believe we get one step further. The following tests where performed with aiosmtpd==1.3.0: Output of the code you requested to be run:
Then I modified /usr/local/lib/python3.6/site-packages/aiosmtpd/controller.py and put some debug statements at the beginning of factory() and _factory_invoker().
As expected executing factory() returns its debug output, whereas executing _factory_invoker() calls both _factory_invoker() as well as factory().
If I explicitely call _factory_invoker() first, then start() doesn't produce a RuntimeError:
|
Interesting! At first glance, it seems that on the failing machine, Python's Yet your last experiment, in which you "pre-initialize" the For some reasons, the spawned thread seems to be unable to write back to the main thread, and that's why Hmm... I don't have a quick answer for this. Please allow me some time to study this interesting situation. PS: This "unable to modify main thread's behavior" totally reminds me of how |
Unfortunately I don't know enough about Pythons threading to debug this alone. |
I suddenly have an inspiration: Within the if self._thread_exception is not None: # pragma: on-wsl
# See comment about WSL1.0 in the _run() method
assert self._thread is not None # Stupid LGTM.com; see github/codeql#4918
raise self._thread_exception can you insert the lines: if not ready_event.is_set():
raise RuntimeError("Server not ready within alotted time.") (The It won't fix the problem, but at least we'll get another control point to observe the behavior. If a RuntimeError gets raised there, we can narrow down the problem. |
Inspired by aio-libs#244
Hello @pepoluan
This resulted in the following output:
So unfortunately still the same error. |
Okay, so at least we know it was not caused by timeout. Let's add another check point. In the middle of these lines: try:
self._testconn()
except Exception:
# We totally don't care of exceptions experienced by _testconn,
# which _will_ happen if factory() experienced problems.
pass
if self._thread_exception is not None:
raise self._thread_exception Please add try:
self._testconn()
except Exception:
# We totally don't care of exceptions experienced by _testconn,
# which _will_ happen if factory() experienced problems.
pass
time.sleep(0.5)
if self._thread_exception is not None:
raise self._thread_exception We try giving additional time for |
Also inspired by aio-libs#244 We add another threading.Event to wait until _factory_invoker() completes. Plus a test case to test this timeout.
Version higher than 1.2.2 cause the server start to fail. See aio-libs/aiosmtpd#244 for more info.
Apparently someone else is running into the same issue, so at least it's not some messed up setting only on my servers. I added the following to
However the output is unchanged:
|
This is seriously strange. The test suite -- which does test the Controller lots of times -- never failed in lots of OSes. Windows, Ubuntu, OpenSUSE, FreeBSD ... they all pass with flying colors.
Okay let's replace the short-ish delay with a longer one. I'm more and more convinced that the problem lies between
self._factory_invoked = threading.Event() # earlier it was .Thread(), and that's a typo
finally:
self._factory_invoked.set()
self._factory_invoked.clear()
if not self._factory_invoked.wait(5.0):
raise TimeoutError("SMTP server not responding within allotted time") I have a feeling that now we'll see |
I applied the diff at the end to
or if I remove
Diff:
|
Hey, someone else here! I've been getting this issue with Python 3.9 in both alpine-based docker images and on my dev machine running Arch Linux, in both cases using a fresh virtualenv created by pipenv. To reproduce this, clone my repository at this commit and replace line 90 in app.py with |
Auuugh, that's a typo by me 😭 Sorry, should have been Got a brainfreeze when typing that line... |
Nice, hopefully we can nail what's going on. I'm cloning it right now... |
OOOOKAY so, thanks to @LeoVerto I managed to nail down the problem (I think). Try editing the
Try doing the two above changes and tell me if it now works. If this works, I'm going to push an urgent bugfix. |
I suspect this is what happened: % python
Python 3.6.9 (default, Jul 17 2020, 12:50:27)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from aiosmtpd.controller import Controller
>>> from aiosmtpd.handlers import Sink
>>> cont = Controller(Sink())
>>> cont.start()
>>> cont.stop()
>>> cont = Controller(Sink(), hostname="")
>>> cont.start()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/pepoluan/projects/aiosmtpd/aiosmtpd/controller.py", line 177, in start
raise RuntimeError("Unknown Error, failed to init SMTP server")
RuntimeError: Unknown Error, failed to init SMTP server
>>> cont.stop() |
Ok so here we go. Just for completeness I tried the suggestions from #244 (comment) again, this time with
But now it gets interesting: When changing
This doesn't fix the problem but shows the cause: The servers are not dual stack, ::1 is unknown to them. And indeed the following doesn't produce an error anymore with aiosmtpd==1.3.0:
Leaving out hostname or passing hostname="" both produce the dreaded RuntimeError. |
Awesome! So at least we found out what's going on, why SMTP was not initialized properly. Or, to be more exact, why triggering SMTP does not work.
Version 1.2.2 gave hostname & port only to asyncio.loop.create_server, which seems to have the superpower of translating "::1" into "127.0.0.1" (or similar). Version 1.2.4 added the capability to detect if Problem is, all my test systems are apparently dual-stack, so I did not caught this behavior, as socket.create_connection will happily try to connect to "::1" Anyways, glad to figure out what's wrong with your experiment ... now I need to step back and do some deep thought + research on how to fully stomp out this issue... |
#244) * Implement _factory_invoked Event * Suppress only socket.timeout exception Other exceptions should bubble up, no longer hidden * Enforce ready_timeout * Floatify AIOSMTPD_CONTROLLER_TIMEOUT value * Update docs & NEWS * Version bump * Add a smarter* way to determine localhost addr * Add test for hostname not specified
I will release v1.3.1 soon; waiting for GA to validate the squamerging to |
Hello @pepoluan thank you very much! Looks very good, except that on my system the error 97 is thrown:
Errno 97 translates to errno.EAFNOSUPPORT, however get_localhost() is catching errno.EADDRNOTAVAIL. If I replace errno.EADDRNOTAVAIL with errno.EAFNOSUPPORT, version 1.3.1 works! |
Thanks! Hmm... seems like different errors for different systems? I'll just change the |
I never received errno 99 (EADDRNOTAVAIL). Only errno 97. Maybe in the environment of @LeoVerto errno 99 was seen? |
In my test system I got EADDRNOTAVAIL, that's why the equality test was against EADDRNOTAVAIL. I've changed it so it's Edit: After some thinking, I think the difference is because on my test systems I disabled IPv6 using sysctl, so the IPv6 modules are still loaded in the kernel, hence EADDRNOTAVAIL ("you want IPv6 address? Sure I can give you that but I'm currently on vacation.") Your kernel probably didn't load the IPv6 module at all, thus EAFNOSUPPORT ("You want what? Nobody here provides what you want.") |
This has fixed the issue for me, thank you so much for the quick debugging and fix, @pepoluan! |
Hello, % sendria --db db.sqlite -d -a
2021-03-05T12:36:02.487786Z no PID file specified; runnning in foreground
2021-03-05T12:36:02.487885Z starting Sendria db=/Users/mysz/Projects/sendria/db.sqlite debug=enabled foreground=true pidfile=None
2021-03-05T12:36:02.491769Z DB initialized
2021-03-05T12:36:02.492011Z webhooks disabled
Traceback (most recent call last):
File "/Users/mysz/Projects/sendria/.venv/bin/sendria", line 33, in <module>
sys.exit(load_entry_point('sendria', 'console_scripts', 'sendria')())
File "/Users/mysz/Projects/sendria/sendria/cli.py", line 296, in main
run_sendria_servers(loop, args)
File "/Users/mysz/Projects/sendria/sendria/cli.py", line 176, in run_sendria_servers
smtp.run(args.smtp_ip, args.smtp_port, args.smtp_auth, args.smtp_ident, args.debug)
File "/Users/mysz/Projects/sendria/sendria/smtp.py", line 69, in run
controller.start()
File "/Users/mysz/Projects/sendria/.venv/lib/python3.9/site-packages/aiosmtpd/controller.py", line 225, in start
raise TimeoutError("SMTP server not responding within allotted time")
TimeoutError: SMTP server not responding within allotted time % python --version
Python 3.9.1
% uname -s
Darwin |
Hi, can you create a new issue instead of replying here? That way we can actually track which issues have been fixed, and by which PR. Would go a long way towards ease of troubleshooting as we can bisect. Because this seems to be caused by a different bug from the 1.3.x issues. |
Hi, sure. I was thinking it can be similar one :) |
After upgrading from version 1.2.2 to 1.2.4 we receive the following error when trying to start the controller:
This error can even be triggered by running the sample code from the documentation:
After executing "controller.start()" the RuntimeError from above appears.
Python version is 3.6.8
OS is Red Hat 7.9
aiosmtpd was installed with pip3. After downgrading via "sudo pip3 install aiosmtpd=1.2.2" everything works again and aiosmtpd receives and processes emails without problems.
The text was updated successfully, but these errors were encountered: