Skip to main content
Glama
process.cpython-312.pyc15 kB
� ���hJ+���dZddlZddlZddlZddlZddlZddlZddlmZddl m Z m Z ddl m Z m Z ddlmZmZej"e�ZGd�d �Zy) z-Process management layer for background jobs.�N)�deque)�datetime�timezone)�Deque�Optional�)� JobStatus� ProcessOutputc���eZdZdZ ddededefd�Zdd�Zdd �Zd e ed eddfd �Z d ede fd�Z de fd�Zdefd�Zde fd�Zdede fd�Zdeefd�Zdeefd�Zdd�Zd�Zy)�ProcessWrapperz<Wrapper for managing background processes with I/O handling.�job_id�command�max_output_sizec�&�||_||_||_d|_d|_d|_|dz}t |��|_t |��|_d|_ d|_ tj�|_ tj�|_y)z�Initialize process wrapper. Args: job_id: Unique identifier for the job command: Shell command to execute max_output_size: Maximum size for output buffers in bytes N�d)�maxlen)r rr�process� started_at� completed_atr� stdout_buffer� stderr_buffer�_stdout_thread�_stderr_thread� threading�Event�_output_complete�Lock� _buffer_lock)�selfr rr� max_liness �W/Users/dylan/Workspace/mcp/servers/mcp-background-job/src/mcp_background_job/process.py�__init__zProcessWrapper.__init__s����� ��� �.���37�� �.2���04���$�s�*� �).�i�)@���).�i�)@���;?���:>��� )��� 1���&�N�N�,����returnNc ���K�|j�td|j�d��� tj|j �}t jd|j�d|j ���tj|tjtjtjddd��|_tjtj�|_|j!�t jd|j�d |jj"���y#t$$r2}t j'd |j�d|���d|_�d}~wwxYw�w) z+Start the process with proper I/O handling.N�Process z is already runningzStarting process �: Tr)�stdout�stderr�stdin�text�bufsize�universal_newlinesz started with PID zFailed to start process )r� RuntimeErrorr �shlex�splitr�logger�info� subprocess�Popen�PIPEr�nowr�utcr�_start_output_threads�pid� Exception�error)r�args�es r!�startzProcessWrapper.start4s���� �<�<� #���$�+�+��6I�J�K� K� ��;�;�t�|�|�,�D� �K�K�+�D�K�K�=��4�<�<�.�I� J�&�+�+��!���!��� �o�o���#'��D�L�'�l�l�8�<�<�8�D�O� � &� &� (� �K�K�(�4�;�;�-�/A�$�,�,�BR�BR�AS�T� U��� � �L�L�3�D�K�K�=��1�#�F� G��D�L� �� �s)�&E2�D D4�3E2�4 E/�=-E*�*E/�/E2c���|j�y|jj�tj|j |jj |jdfd��|_|jj�tj|j |jj|jdfd��|_ |jj�y)z0Start threads to read process stdout and stderr.Nr(T)�targetr<�daemonr)) rr�clearr�Thread� _read_streamr(rrr>r)rr�rs r!r8z$ProcessWrapper._start_output_threadsWs��� �<�<� � � ���#�#�%�(�.�.��$�$��,�,�%�%�t�'9�'9�8�D�� ��� ���!�!�#�(�.�.��$�$��,�,�%�%�t�'9�'9�8�D�� ��� ���!�!�#r#�buffer� stream_namec �"� |j�}|sn`|jd�}|j5|j|�ddd�tj d|j �d|�d|����s tj d|�d|j ���y#1swY�YxYw#t$r2}tjd|�d|j �d|���Yd}~�hd}~wwxYw#tj d|�d|j ���wxYw) z�Read from a process stream and buffer the output. Args: stream: Process stream (stdout or stderr) buffer: Deque buffer to store lines stream_name: Name of stream for logging z Nr&� r'zError reading z for process zFinished reading ) �readline�rstripr�appendr1�debugr r:r;)r�streamrFrG�liner=s r!rDzProcessWrapper._read_streamns��� V�����(�����{�{�6�*���&�&��M�M�$�'�'�� � �x�� � �}�A�k�]�"�T�F�K�L��� �L�L�,�[�M��t�{�{�m�T� U�'�&�� � X� �L�L�>�+��m�D�K�K�=�PR�ST�RU�V� W� W�� X�� �L�L�,�[�M��t�{�{�m�T� U�sF�1B)�B�1B)�6C'�B&�"B)�) C$�2(C�C'�C$�$C'�''Dr+c��TK�|j�td|j�d���|jj�td|j�d��� |j5t |j �}t |j�}ddd�|jjj|�|jd�s%|jjjd�|jjj�tjd|j�d|j����tjd��d{���|j5t!|j �d}t!|j�d}ddd�t#dj%�dj%�� �S#1swY��IxYw7��#1swY�CxYw#t&$r+}tj)d |j�d|����d}~wwxYw�w) a+Send input to process stdin and return immediate output. Args: text: Text to send to stdin Returns: ProcessOutput with any immediate stdout/stderr output Raises: RuntimeError: If process is not running or stdin is not available Nr&z is not runningz stdin is not available� zSent input to process r'g�������?�r(r)zError sending input to process )rr.r r*r�lenrr�write�endswith�flushr1rM�strip�asyncio�sleep�listr �joinr:r;)rr+� stdout_before� stderr_before� stdout_new� stderr_newr=s r!� send_inputzProcessWrapper.send_input�s����� �<�<� ���$�+�+��o�F�G� G� �<�<� � � %���$�+�+��6M�N�O� O� ��"�"� #�D�$6�$6� 7� � #�D�$6�$6� 7� �#� �L�L� � � $� $�T� *��=�=��&�� � �"�"�(�(��.� �L�L� � � $� $� &� �L�L�1�$�+�+��b������O� P��-�-��$� $� $��"�"�!�$�"4�"4�5�m�n�E� �!�$�"4�"4�5�m�n�E� �#�!��y�y��,�T�Y�Y�z�5J�� �)#�"�� %��#�"��� � �L�L�:�4�;�;�-�r�!��M� N� �� �sg�AH(� G1�$+G�CG1�!G#�"G1�21G%�#2G1�H(�G � G1�%G.�*G1�1 H%�:&H � H%�%H(c�H�|j�tjS|jj�}|�tjS|dk(rD|j �(t jtj�|_tjS|dk(s|dk(rD|j �(t jtj�|_tjS|j �(t jtj�|_tjS)zUGet current process status. Returns: Current job status ri����i����) rr �FAILED�poll�RUNNINGrrr6rr7� COMPLETED�KILLED)r� exit_codes r!� get_statuszProcessWrapper.get_status�s��� �<�<� ��#�#� #��L�L�%�%�'� � � ��$�$� $� �!�^�� � �(�$,�L�L����$>��!��&�&� &� �"�_� �S� 0�� � �(�$,�L�L����$>��!��#�#� #�� � �(�$,�L�L����$>��!��#�#� #r#c�$�|j�y|jj��y tjd|j�d|jj �d��|jj � |jjd��tjd|j�d ��tjtj�|_y #tj$rZtjd|j�d ��|jj�|jj�Y��wxYw#t"$r/}tj%d |j�d |���Yd}~yd}~wwxYw)zpKill the process. Returns: True if process was killed, False if already terminated NFzKilling process z (PID: �)���timeoutr&z terminated gracefullyz, did not terminate gracefully, force killingTzError killing process r')rrcr1r2r r9� terminate�waitr3�TimeoutExpired�warning�killrr6rr7rr:r;)rr=s r!rrzProcessWrapper.kill�sB�� �<�<� �� �<�<� � � � *�� � �K�K�*�4�;�;�-�w�t�|�|�?O�?O�>P�PQ�R� S� �L�L� "� "� $� $�� � �!�!�!�!�,�� � �h�t�{�{�m�3I�J�K�!)� � �X�\�\� :�D� ����,�,� $�����t�{�{�m�+W�X��� � �!�!�#�� � �!�!�#�  $��� � �L�L�1�$�+�+��b���D� E��� �s=�AE�??C'�>(E�'A*E�E�E�E� F� %F � Fc���|j5t|j�}t|j�}ddd�t dj �dj ���S#1swY�4xYw)znGet all captured output. Returns: ProcessOutput containing all stdout and stderr NrQrR�rrZrrr r[)r� stdout_lines� stderr_liness r!� get_outputzProcessWrapper.get_output�sa�� � � ��� 2� 2�3�L��� 2� 2�3�L����9�9�\�*�4�9�9�\�3J� � � � �s �+A+�+A4�linesc��|j5|dkDrt|j�| dng}|dkDrt|j�| dng}ddd�t dj �dj ���S#1swY�4xYw)z�Get last N lines of output. Args: lines: Number of lines to return from the end Returns: ProcessOutput containing last N lines of stdout and stderr rNrQrRrt)rrxrurvs r!� tail_outputzProcessWrapper.tail_output s���� � �@E�� �4�� 2� 2�3�U�F�G�<�r�L�@E�� �4�� 2� 2�3�U�F�G�<�r�L�� ��9�9�\�*�4�9�9�\�3J� � � � �s �AB�B c�P�|j�y|jj�S)z�Get process exit code if available. Returns: Exit code if process has terminated, None if still running N)rrcrEs r!� get_exit_codezProcessWrapper.get_exit_codes$�� �<�<� ���|�|� � �"�"r#c�H�|j�y|jjS)ztGet process ID if available. Returns: Process ID if process is running, None otherwise N)rr9rEs r!�get_pidzProcessWrapper.get_pid%s!�� �<�<� ���|�|���r#c�0�|jr*|jj��|j�|jr6|jj �r|jj d��|j r6|j j �r|j j d��|jr�|jjr$|jjj�|jjr$|jjj�|jjr$|jjj�tjd|j���y)zClean up process resources.NrrlzCleaned up process )rrcrrr�is_aliver[rr*�closer(r)r1rMr rEs r!�cleanupzProcessWrapper.cleanup/s�� �<�<�D�L�L�-�-�/�7� �I�I�K� � � �4�#6�#6�#?�#?�#A� � � � $� $�Q� $� /� � � �4�#6�#6�#?�#?�#A� � � � $� $�Q� $� /� �<�<��|�|�!�!�� � �"�"�(�(�*��|�|�"�"�� � �#�#�)�)�+��|�|�"�"�� � �#�#�)�)�+�� � �*�4�;�;�-�8�9r#c�4� |j�y#YyxYw)zDestructor to ensure cleanup.N)r�rEs r!�__del__zProcessWrapper.__del__Fs�� � �L�L�N�� � �s��)i�)r$N)�__name__� __module__� __qualname__�__doc__�str�intr"r>r8rrDr r`r rh�boolrrrwrzrr|r~r�r��r#r!r r s���F�AQ�-��-�$'�-�:=�-�>!�F$�.V�5��:�V�C�V�D�V�8.�S�.�]�.�`$�I�$�6$�d�$�L  �M�  � �� �� �$#�x��}�#� ��#�� �:�.r#r )r�rX�loggingr/r3r�time� collectionsrrr�typingrr�modelsr r � getLoggerr�r1r r�r#r!�<module>r�sD��3��� ��� ��'�"�,� �� � �8� $��y�yr#

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dylan-gluck/mcp-background-job'

If you have feedback or need assistance with the MCP directory API, please join our Discord server