Skip to content

Commit

Permalink
feat: allow running server on custom port
Browse files Browse the repository at this point in the history
fixes #75
  • Loading branch information
kantord committed Aug 21, 2023
1 parent 1dfcaa3 commit 01f36d9
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 36 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ jobs:
- name: Run pytest
run: |
poetry run pytest . -vvs
poetry run pytest . -vvs --timeout=60
23 changes: 23 additions & 0 deletions docs/server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- markdownlint-disable MD046 -->
# SeaGOAT-server

The seagoat-server is an integral component of the Seagoat command-line tool
designed to analyze your codebase and create vector embeddings for it.

While it serves as a backend for the command-line tool, also allows you to
use it through HTTP to build your own SeaGOAT-based applications.

## Starting the server

To boot up the server for a specific repository, use:

```bash
seagoat-server start <repo_path> [--port=<custom_port>]
```

* `repo_path`: Path to your Git repository
* `--port`: (Optional) Run the server on a specific port

If you don't specify a custom port, a random port will be assigned to your
server. Don't worry, SeaGOAT will still be able to automatically find
the server corresponding to a specific repository.
6 changes: 6 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,9 @@ theme:
features:
- content.action.edit
- content.code.copy
- navigation.instant
- navigation.tracking
nav:
- Getting Started: index.md
- Usage Reference: usage.md
- SeaGOAT Server: server.md
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ python-semantic-release = "^8.0.4"
pytest-sugar = "^0.9.7"
pytest-profiling = "^1.7.0"
pytest-timeout = "^2.1.0"
psutil = "^5.9.5"

[build-system]
requires = ["poetry-core"]
Expand Down Expand Up @@ -134,4 +135,4 @@ dist_glob_patterns = ["dist/*"]
upload_to_vcs_release = true

[tool.pytest.ini_options]
timeout = 30
timeout = 15
16 changes: 11 additions & 5 deletions seagoat/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,10 @@ def get_free_port():
return port


def start_server(repo_path, port=None):
def start_server(repo_path, custom_port=None):
os.environ["TOKENIZERS_PARALLELISM"] = "false"
app = create_app(repo_path)
port = custom_port

if port is None:
port = get_free_port()
Expand Down Expand Up @@ -125,8 +126,9 @@ def wait_for(condition_function, timeout, period=0.05):
time.sleep(period)


def get_server(repo_path, port=None):
def get_server(repo_path, custom_port=None):
server_info_file = get_server_info_file(repo_path)
port = None

if os.path.exists(server_info_file):
host, port, _, server_address = load_server_info(server_info_file)
Expand All @@ -136,11 +138,14 @@ def get_server(repo_path, port=None):
return server_address
os.remove(server_info_file)

if custom_port is not None:
port = custom_port

os.environ["TOKENIZERS_PARALLELISM"] = "true"
temp_app = create_app(repo_path)
del temp_app

start_server(str(repo_path), port)
start_server(str(repo_path), custom_port=port)

wait_for(lambda: os.path.exists(server_info_file), timeout=60)

Expand All @@ -161,9 +166,10 @@ def server():

@server.command()
@click.argument("repo_path")
def start(repo_path):
@click.option("--port", type=int, help="The port to start the server on", default=None)
def start(repo_path, port):
"""Starts the server."""
get_server(repo_path, port=None)
get_server(repo_path, custom_port=port)
click.echo("Server running.")


Expand Down
24 changes: 24 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import multiprocessing
import os
import shutil
import subprocess
import tempfile
from collections import defaultdict
from contextlib import contextmanager
from datetime import datetime
from datetime import timedelta
from datetime import timezone
Expand Down Expand Up @@ -390,3 +392,25 @@ def client(repo):
def mock_queue(client):
# pylint: disable=protected-access
yield client._mock_queue


@pytest.fixture
def managed_process():
processes = []

@contextmanager
def _process(*args, **kwargs):
proc = subprocess.Popen(*args, **kwargs)
processes.append(proc)
try:
yield proc
finally:
proc.terminate()
proc.wait()
processes.remove(proc)

yield _process

for proc in processes:
proc.terminate()
proc.wait()
57 changes: 29 additions & 28 deletions tests/test_server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# pylint: disable=no-member
import copy
import json
import os
import re
import subprocess
from unittest.mock import ANY
Expand All @@ -10,8 +11,11 @@
import requests

from seagoat import __version__
from seagoat.server import get_server_info_file
from seagoat.server import get_status_data
from seagoat.server import load_server_info
from seagoat.server import server as seagoat_server
from seagoat.server import wait_for


def normalize_full_paths(data, repo):
Expand Down Expand Up @@ -126,11 +130,14 @@ def assert_server_status(repo, running):


def simulate_server_dying(repo):
pid = get_status_data(repo.working_dir)["pid"]
try:
pid = get_status_data(repo.working_dir)["pid"]

process = psutil.Process(pid)
process.terminate()
process.wait(timeout=10)
process = psutil.Process(pid)
process.terminate()
process.wait(timeout=10)
except psutil.TimeoutExpired:
pass


@pytest.mark.usefixtures("server")
Expand Down Expand Up @@ -186,29 +193,23 @@ def test_version_option(runner):
assert result.output.strip() == f"seagoat, version {__version__}"


@pytest.mark.parametrize("port", [8080, 8081])
def test_start_server_on_specific_port(port, repo):
subprocess.run(
[
"python",
"-m",
"seagoat.server",
"start",
"--port",
str(port),
repo.working_dir,
],
capture_output=True,
text=True,
check=False,
)
@pytest.mark.parametrize("custom_port", [7483, 99081])
def test_start_server_on_specific_port(custom_port, repo, mocker, managed_process):
mocker.patch("seagoat.server.TaskQueue")

response = requests.get(f"http://localhost:{port}/query/hello")
assert response.status_code == 200
server_cmd = [
"python",
"-m",
"seagoat.server",
"start",
"--port",
str(custom_port),
repo.working_dir,
]

with managed_process(server_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE):
wait_for(lambda: os.path.exists(get_server_info_file(repo.working_dir)), 8)

# subprocess.run(
# ["python", "-m", "seagoat.server", "stop", repo.working_dir],
# capture_output=True,
# text=True,
# check=False,
# )
server_info_file = get_server_info_file(repo.working_dir)
_, _, _, server_address = load_server_info(server_info_file)
assert str(custom_port) in server_address

0 comments on commit 01f36d9

Please sign in to comment.