Skip to content
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

Add Rservice #80

Open
wants to merge 12 commits into
base: dev
Choose a base branch
from
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# bedboss
<h1 align="center">bedboss</h1>

<div align="center">

[![PEP compatible](https://pepkit.github.io/img/PEP-compatible-green.svg)](https://pep.databio.org/)
![Run pytests](https://github.com/bedbase/bedboss/workflows/Run%20instalation%20test/badge.svg)
[![pypi-badge](https://img.shields.io/pypi/v/bedboss?color=%2334D058)](https://pypi.org/project/bedboss)
[![pypi-version](https://img.shields.io/pypi/pyversions/bedboss.svg?color=%2334D058)](https://pypi.org/project/bedboss)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![Github badge](https://img.shields.io/badge/source-github-354a75?logo=github)](https://github.com/databio/bedboss)

</div>

---

**Documentation**: <a href="https://docs.bedbase.org/bedboss" target="_blank">https://docs.bedbase.org/bedboss</a>
Expand Down
82 changes: 82 additions & 0 deletions bedboss/bedstat/r_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import subprocess
import socket
import signal
import os


class RServiceManager:
"""
A class to manage the lifecycle of an R service, allowing files to be processed through the service.

Attributes:
r_script_path (str): Path to the R script that starts the service.
host (str): Host address for the socket connection.
port (int): Port number for the socket connection.
process (subprocess.Popen): The process running the R service.
"""

def __init__(self, r_script_path="tools/r-service.R", host="127.0.0.1", port=8888):
"""
Initializes the RServiceManager with the given R script path, host, and port.

Args:
r_script_path (str): Path to the R script that starts the service.
host (str): Host address for the socket connection. Default is "127.0.0.1".
port (int): Port number for the socket connection. Default is 8888.
"""
self.r_script_path = r_script_path
self.host = host
self.port = port
self.process = None

def start_service(self):
"""
Starts the R service by running the R script in a subprocess.
"""
cmd = ["Rscript", self.r_script_path]
self.process = subprocess.Popen(cmd, shell=False, preexec_fn=os.setsid)
print(f"Running R process with PID: {self.process.pid}")

def run_file(self, file_path):
"""
Sends a file path to the R service for processing.

Args:
file_path (str): The path to the file to be processed by the R service.
"""
try:
s = socket.socket()
s.connect((self.host, self.port))
s.send(file_path.encode())
s.close()
except ConnectionRefusedError:
print("Connection refused. Make sure the R service is running.")

def terminate_service(self):
"""
Terminates the R service by sending a termination signal and ensuring the process is stopped.
"""
self.run_file("done") # send secrete "terminate" code
if self.process:
self.process.terminate()
try:
self.process.wait(timeout=5)
except subprocess.TimeoutExpired:
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
print("R process terminated.")


# TODO: "tools/r-service.R" needs to be embedded in the package


# Start the R service at the beginning of the pipeline
rsm = RServiceManager("tools/r-service.R")
rsm.start_service()


# Run any BED files through bedstat
rsm.run_file("bedstat/data/beds/bed1.bed")
rsm.run_file("../../test/data/bed/simpleexamples/bed1.bed")

# After the pipeline finishes, terminate the R service
rsm.terminate_service()
21 changes: 21 additions & 0 deletions bedboss/bedstat/tools/r-service.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# This function should run the process
processBED = function(path, client, port) {
message("Processing BED file: ", path)
if (path == "done") { # Secret shutdown signal
message("Received done signal")
assign("done", TRUE, envir=.GlobalEnv)
return(0)
}
if (!file.exists(path)) {
message("File not found: ", path)
return(1)
}
return(1)
}

message("Starting R server")
svSocket::start_socket_server(procfun=processBED)
message ("R server started")
while (!exists("done")) Sys.sleep(1)

message("Shutting down R service")
Loading