Skip to content

Commit

Permalink
Show the possibly listening process in the AlreadyRunning exception m…
Browse files Browse the repository at this point in the history
…essage, refs ClearcodeHQ#133
  • Loading branch information
mmaslowskicc committed Jan 23, 2017
1 parent d86169d commit a3f896f
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
40 changes: 39 additions & 1 deletion src/mirakuru/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Mirakuru exceptions."""

import psutil


class ExecutorError(Exception):
"""Base exception for executor failures."""
Expand Down Expand Up @@ -45,8 +47,43 @@ class AlreadyRunning(ExecutorError):
When some other process (not necessary executor) seems to be started with
same configuration we can't bind to same port.
The exception message is less useful for executors not using TCP ports.
"""

def __init__(self, executor):
"""
Initialize and detect what service is listening on the configured port.
:param mirakuru.base.Executor executor: for which exception occurred
"""
super(AlreadyRunning, self).__init__(executor)
try:
self.port = getattr(executor, 'port')
except AttributeError:
self.port = None
if self.port:
# The pid field contains an integer process ID or None if the
# process belongs to a different user. Multiple processes can
# listen on the same port.
pids = [
sconn.pid
for sconn in psutil.net_connections(kind='tcp')
if sconn.pid and sconn.laddr[1] == self.port]
processes = []
for pid in pids:
try:
processes.append(
'%r[%d]' % (psutil.Process(pid).cmdline(), pid))
except psutil.NoSuchProcess:
processes.append('exited[%d]' % pid)
if not processes:
self.listening_service = '[unknown]'
else:
self.listening_service = ' '.join(processes)
else:
self.listening_service = '[unknown]'

def __str__(self):
"""
Return Exception's string representation.
Expand All @@ -57,7 +94,8 @@ def __str__(self):
return ("Executor {exc.executor} seems to be already running. "
"It looks like the previous executor process hasn't been "
"terminated or killed. Also there might be some completely "
"different service listening on {exc.executor.port} port."
"different service listening on {exc.port} port. Services "
"found running on that port: {exc.listening_service}."
.format(exc=self))


Expand Down
4 changes: 4 additions & 0 deletions tests/executors/test_http_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys
import socket
from functools import partial
import shlex

import pytest
from mock import patch
Expand Down Expand Up @@ -124,6 +125,9 @@ def test_fail_if_other_executor_running():
with executor2:
pass
assert 'seems to be already running' in str(exc)
expected_process = '%r[%d]' % (
shlex.split(http_server_cmd), executor.process.pid)
assert expected_process in str(exc)


@patch.object(HTTPExecutor, 'DEFAULT_PORT', PORT)
Expand Down

0 comments on commit a3f896f

Please sign in to comment.