2015-01-25 16 views
7

Tôi đang cố gắng tiêu thụ luồng sự kiện được cung cấp bởi Kubernetes api bằng mô-đun requests. Tôi đã gặp phải vấn đề về bộ đệm là : mô-đun requests dường như bị trễ bởi một sự kiện.Đọc phản hồi trực tuyến http bằng thư viện "yêu cầu" Python

Tôi có mã mà trông giống như sau:

r = requests.get('http://localhost:8080/api/v1beta1/watch/services', 
       stream=True) 

for line in r.iter_lines(): 
    print 'LINE:', line 

Như Kubernetes phát ra thông báo sự kiện, mã này sẽ chỉ hiển thị các sự kiện cuối cùng phát ra khi một sự kiện mới đến, mà làm cho nó gần như hoàn toàn vô dụng cho mã cần phản hồi với dịch vụ thêm/xóa sự kiện.

tôi đã giải quyết điều này bằng cách đẻ trứng curl trong một tiến trình con thay vì sử dụng thư viện requests:

p = subprocess.Popen(['curl', '-sfN', 
         'http://localhost:8080/api/watch/services'], 
        stdout=subprocess.PIPE, 
        bufsize=1) 

for line in iter(p.stdout.readline, b''): 
    print 'LINE:', line 

này hoạt động, nhưng tại các chi phí của một số linh hoạt. Có cách nào để tránh sự cố lưu vào bộ đệm này với thư viện requests không?

Trả lời

5

Hành vi này là do triển khai lỗi của phương pháp iter_lines trong thư viện requests.

iter_lines lặp lại nội dung phản hồi trong chunk_size khối dữ liệu bằng cách sử dụng trình lặp iter_content. Nếu có ít hơn chunk_size byte dữ liệu có sẵn để đọc từ máy chủ từ xa (thường sẽ là trường hợp khi đọc dòng cuối cùng của đầu ra), hoạt động đọc sẽ chặn cho đến khi chunk_size bytes của dữ liệu có sẵn.

Tôi đã viết iter_lines thói quen của riêng tôi mà hoạt động một cách chính xác:

import os 


def iter_lines(fd, chunk_size=1024): 
    '''Iterates over the content of a file-like object line-by-line.''' 

    pending = None 

    while True: 
     chunk = os.read(fd.fileno(), chunk_size) 
     if not chunk: 
      break 

     if pending is not None: 
      chunk = pending + chunk 
      pending = None 

     lines = chunk.splitlines() 

     if lines and lines[-1]: 
      pending = lines.pop() 

     for line in lines: 
      yield line 

    if pending: 
     yield(pending) 

này hoạt động vì os.read sẽ trả ít hơn chunk_size byte dữ liệu thay vì chờ đợi cho một bộ đệm để điền vào.

+0

Có thể lập luận rằng việc triển khai nào là chính xác - bạn sẽ chèn một "ngắt dòng logic hợp lý" nếu có thêm dữ liệu. Cách tiếp cận chính xác dường như là tìm ra tổng kích thước của dữ liệu (chỉ định một yêu cầu cho truyền thông TCP) và chỉ sử dụng đọc một phần ở đầu đã biết. –

+0

Tôi không nghĩ rằng bạn có thể lập luận rằng việc triển khai hiện tại là chính xác. Mỏ chưa trải qua thử nghiệm nghiêm ngặt, nhưng nó chắc chắn hoạt động tốt hơn. Việc triển khai chính xác hơn - lý tưởng được gửi dưới dạng bản vá thượng nguồn - sẽ cực kỳ hữu ích. – larsks

+0

@ivan_pozdeev * "Cách tiếp cận chính xác dường như tìm ra tổng kích thước dữ liệu (chỉ định một yêu cầu cho truyền thông TCP)" * - Không, TCP là luồng * và có thể có độ dài vô hạn. Tôi không chắc bạn đã nghe về điều đó nhưng về cơ bản là không đúng sự thật. –

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