Skip to content

Commit

Permalink
service exposes inactivity
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrei Neagu committed Oct 23, 2023
1 parent 63ed455 commit 40bc314
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 7 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/check-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ jobs:
- name: Checkout repo content
uses: actions/checkout@v2
- name: ooil version
uses: docker://itisfoundation/ci-service-integration-library:v1.0.3-dev-4
uses: docker://itisfoundation/ci-service-integration-library:v1.0.3-dev-8
with:
args: ooil --version
- name: Assemble docker-compose spec
uses: docker://itisfoundation/ci-service-integration-library:v1.0.3-dev-4
uses: docker://itisfoundation/ci-service-integration-library:v1.0.3-dev-8
with:
args: ooil compose
- name: Build all images if multiple
uses: docker://itisfoundation/ci-service-integration-library:v1.0.3-dev-4
uses: docker://itisfoundation/ci-service-integration-library:v1.0.3-dev-8
with:
args: docker-compose build
5 changes: 5 additions & 0 deletions .osparc/jupyter-math/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ paths-mapping:
outputs_path: /home/jovyan/work/outputs
state_paths:
- /home/jovyan/work/workspace
callbacks-mapping:
inactivity:
service: container
command: "/path/to/your/inactivity/hook"
timeout: 1
7 changes: 5 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ RUN jupyter serverextension enable voila && \
# Import matplotlib the first time to build the font cache.
ENV XDG_CACHE_HOME /home/$NB_USER/.cache/
RUN MPLBACKEND=Agg .venv/bin/python -c "import matplotlib.pyplot" && \
fix-permissions /home/$NB_USER
# run fix permissions only once. This can be probably optimized, so it is faster to build
fix-permissions /home/$NB_USER
# run fix permissions only once. This can be probably optimized, so it is faster to build

# copy README and CHANGELOG
COPY --chown=$NB_UID:$NB_GID CHANGELOG.md ${NOTEBOOK_BASE_DIR}/CHANGELOG.md
Expand All @@ -91,6 +91,9 @@ ENV JP_LSP_VIRTUAL_DIR="/home/${NB_USER}/.virtual_documents"
# Copying boot scripts
COPY --chown=$NB_UID:$NB_GID docker /docker

RUN chmod +x /docker/inactivity.py \
&& chmod +x /docker/kernel_cehcker.py

RUN echo 'export PATH="/home/${NB_USER}/.venv/bin:$PATH"' >> "/home/${NB_USER}/.bashrc"

EXPOSE 8888
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ define _bumpversion
# upgrades as $(subst $(1),,$@) version, commits and tags
@docker run -it --rm -v $(PWD):/${DOCKER_IMAGE_NAME} \
-u $(shell id -u):$(shell id -g) \
itisfoundation/ci-service-integration-library:v1.0.3-dev-4 \
itisfoundation/ci-service-integration-library:v1.0.3-dev-8 \
sh -c "cd /${DOCKER_IMAGE_NAME} && bump2version --verbose --list --config-file $(1) $(subst $(2),,$@)"
endef

Expand All @@ -49,7 +49,7 @@ version-patch version-minor version-major: .bumpversion.cfg ## increases service
compose-spec: ## runs ooil to assemble the docker-compose.yml file
@docker run -it --rm -v $(PWD):/${DOCKER_IMAGE_NAME} \
-u $(shell id -u):$(shell id -g) \
itisfoundation/ci-service-integration-library:v1.0.3-dev-4 \
itisfoundation/ci-service-integration-library:v1.0.3-dev-8 \
sh -c "cd /${DOCKER_IMAGE_NAME} && ooil compose"

build: | compose-spec ## build docker image
Expand Down
1 change: 1 addition & 0 deletions docker/entrypoint.bash
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,5 @@ chmod gu-w "/home/${NB_USER}/work"

echo
echo "$INFO" "Starting notebook ..."
exec gosu "$NB_USER" /docker/kernel_cehcker.py &
exec gosu "$NB_USER" /docker/boot_notebook.bash
9 changes: 9 additions & 0 deletions docker/inactivity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

#!/home/jovyan/.venv/bin/python

# prints the result of the inactivity command

import requests

r = requests.get("http://localhost:9000")
print(r.text)
90 changes: 90 additions & 0 deletions docker/kernel_cehcker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/home/jovyan/.venv/bin/python


import asyncio
import json
import requests
from datetime import datetime
import tornado
from contextlib import suppress
from typing import Final


KERNEL_BUSY_CHECK_INTERVAL_S: Final[float] = 5


class JupyterKernelChecker:
BASE_URL = "http://localhost:8888"
HEADERS = {"accept": "application/json"}

def __init__(self) -> None:
self.last_busy: datetime| None = None

def _get(self, path: str) -> dict:
r = requests.get(f'{self.BASE_URL}{path}', headers=self.HEADERS)
return r.json()

def _are_kernels_busy(self)-> bool:
json_response = self._get("/api/kernels")

are_kernels_busy = False

for kernel_data in json_response:
kernel_id = kernel_data["id"]

kernel_info = self._get(f"/api/kernels/{kernel_id}")
if kernel_info["execution_state"] != "idle":
are_kernels_busy = True

return are_kernels_busy

def check(self):
are_kernels_busy = self._are_kernels_busy()
print(f"{are_kernels_busy=}")

if not are_kernels_busy:
self.last_busy = None

if are_kernels_busy and self.last_busy is None:
self.last_busy = datetime.utcnow()


def get_idle_seconds(self)-> float:
if self.last_busy is None:
return 0

return (datetime.utcnow() - self.last_busy).total_seconds()

async def run(self):
while True:
with suppress(Exception):
self.check()
await asyncio.sleep(KERNEL_BUSY_CHECK_INTERVAL_S)



kernel_checker = JupyterKernelChecker()


class MainHandler(tornado.web.RequestHandler):
def get(self):
idle_seconds = kernel_checker.get_idle_seconds()
response = (
{"is_inactive": True, "seconds_inactive" : idle_seconds}
if idle_seconds > 0 else
{"is_inactive": False, "seconds_inactive" : None}
)
self.write(json.dumps(response))


def make_app()-> tornado.web.Application:
return tornado.web.Application([(r"/", MainHandler)])

async def main():
app = make_app()
app.listen(9000)
asyncio.create_task(kernel_checker.run())
await asyncio.Event().wait()

if __name__ == "__main__":
asyncio.run(main())

0 comments on commit 40bc314

Please sign in to comment.