2013-05-04 32 views
9

Tôi đang cố sử dụng cần tây để lên lịch và chạy các nhiệm vụ trên một nhóm máy chủ. Mỗi nhiệm vụ là hơi dài chạy (vài giờ), và liên quan đến việc sử dụng subprocess để gọi một chương trình nhất định với các đầu vào nhất định. Chương trình này tạo ra rất nhiều đầu ra cả trong stdout và stderr.Kết quả luồng trong cần tây

Có cách nào để hiển thị đầu ra do chương trình tạo cho khách hàng trong thời gian thực gần không? Dòng đầu ra, để khách hàng có thể xem đầu ra được spewed bởi nhiệm vụ đang chạy trên máy chủ mà không cần đăng nhập vào máy chủ?

+0

Nhiệm vụ cần tây của bạn là gì khi chương trình khác chạy? Bạn chỉ đang sử dụng 'subprocess.call'? –

+0

Yup chỉ là một subprocess.call. –

Trả lời

11

Bạn không chỉ định nhiều yêu cầu và ràng buộc. Tôi sẽ giả sử bạn đã có một trường hợp redis một nơi nào đó.

Những gì bạn có thể làm là đọc các đầu ra từ dòng quá trình khác do dòng và xuất bản nó qua redis:

Dưới đây là một ví dụ trong đó bạn có thể echo dữ liệu vào một tập tin /tmp/foo để thử nghiệm:

import redis 
redis_instance = redis.Redis() 
p = subprocess.Popen(shlex.split("tail -f /tmp/foo"), stdout=subprocess.PIPE) 

while True: 
    line = p.stdout.readline() 
    if line: 
     redis_instance.publish('process log', line) 
    else: 
     break 

Trong một quy trình riêng biệt:

import redis 

redis_instance = redis.Redis() 
pubsub = redis_instance.pubsub() 
pubsub.subscribe('process log') 

while True: 
    for message in pubsub.listen(): 
     print message # or use websockets to comunicate with a browser 

Nếu bạn muốn quá trình kết thúc, bạn có thể ví dụ gửi một "bỏ thuốc lá" sau khi nhiệm vụ cần tây được thực hiện.

Bạn có thể sử dụng các kênh khác nhau (chuỗi trong subscribe) để tách đầu ra khỏi các quy trình khác nhau.

Bạn cũng có thể lưu trữ dữ liệu ghi nhận của bạn trong redis, nếu bạn muốn,

redis_instance.rpush('process log', message) 

và sau đó lấy nó đầy đủ.

5

Một cách tôi xem làm thế nào để làm điều đó là để viết Logger tùy chỉnh mà sẽ được sử dụng cho stderr và stdout (xem docs:

from celery.app.log import Logger 
Logger.redirect_stdouts_to_logger(MyLogger()) 

logger của bạn có thể lưu dữ liệu vào cơ sở dữ liệu, Memcached, Redis hoặc bất cứ điều gì chia sẻ lưu trữ mà bạn sẽ sử dụng để có được những dữ liệu

tôi không chắc chắn về cấu trúc của các logger, nhưng tôi đoán điều gì đó như thế này sẽ làm việc:.

from logging import Logger 

class MyLogger(Logger): 
    def log(lvl, msg): 
     # Do something with the message 
+0

@anand_trex bạn đã thử cái này chưa? – AJP

+0

Tôi không thoải mái trộn ghi nhật ký và phát trực tuyến kết quả. Vì đây là loại hack, tôi sẽ không sử dụng giải pháp này. –

2

Đây là một câu hỏi cũ nhưng nó vẫn còn khá nhiều kết quả duy nhất về chủ đề cụ thể này.

Đây là cách tôi đi về nó, Tôi tạo ra một đối tượng tập tin giống như đơn giản mà công bố một kênh cụ thể hơn Redis

class RedisFileObject(object): 
    def __init__(self, _key): 
     self.connection = redis.Redis() 
     self.key = _key 
     self.connection.publish('debug', 'Created channel %s' % self.key) 

    def write(self, data): 
     self.connection.publish(self.key, data) 

    def close(self): 
     pass 

Tôi có một BaseTask từ đó tất cả các nhiệm vụ của tôi được thừa hưởng chức năng khác nhau bao gồm. cái này thay thế stdout và stderr bằng đối tượng giống như tệp Redis.

def capture_output(self): 
    sys.stdout = RedisFileObject(self.request.id) 
    sys.stderr = RedisFileObject(self.request.id) 

Từ đó mọi thứ được viết bằng stdout/stderr sẽ được chuyển tiếp đến kênh Redis được đặt tên sau id công việc.

Các vấn đề liên quan