2008-09-29 31 views

Trả lời

5

GAE là công cụ rất hữu ích để xây dựng các ứng dụng web có thể mở rộng. Một số hạn chế được chỉ ra bởi nhiều người không hỗ trợ cho các tác vụ nền, thiếu các nhiệm vụ định kỳ và giới hạn nghiêm ngặt về thời gian mỗi yêu cầu HTTP mất đi, nếu yêu cầu vượt quá giới hạn thời gian đó. .

Cách chạy tác vụ nền?
Trong GAE, mã được thực thi chỉ khi có yêu cầu HTTP. Có một giới hạn thời gian nghiêm ngặt (tôi nghĩ 10 giây) về việc mã có thể mất bao lâu. Vì vậy, nếu không có yêu cầu thì mã sẽ không được thực thi. Một trong những công việc được đề xuất xung quanh là sử dụng một hộp bên ngoài để gửi yêu cầu liên tục, do đó, loại tạo ra một nhiệm vụ nền. Nhưng đối với điều này chúng ta cần một hộp bên ngoài và bây giờ chúng ta phụ thuộc vào một yếu tố nữa. Cách khác là gửi 302 phản hồi chuyển hướng để khách hàng gửi lại yêu cầu, điều này cũng làm cho chúng ta phụ thuộc vào yếu tố bên ngoài là khách hàng. Điều gì xảy ra nếu hộp bên ngoài đó chính là GAE? Tất cả những người đã sử dụng ngôn ngữ chức năng mà không hỗ trợ xây dựng vòng lặp trong ngôn ngữ nhận thức được sự thay thế tức là thay thế cho vòng lặp. Vì vậy, những gì nếu chúng ta hoàn thành một phần của tính toán và làm một HTTP GET trên cùng một url với thời gian rất ngắn ra nói 1 giây? Điều này tạo ra một vòng lặp (đệ quy) trên mã php chạy trên apache.

 
<?php 
$i = 0; 
if(isset($_REQUEST["i"])){ 
     $i= $_REQUEST["i"]; 
    sleep(1); 
} 
$ch = curl_init("http://localhost".$_SERVER["PHP_SELF"]."?i=".($i+1)); 
curl_setopt($ch, CURLOPT_HEADER, 0); 
curl_setopt($ch, CURLOPT_TIMEOUT, 1); 
curl_exec($ch); 
print "hello world\n"; 
?> 

Một số cách thức này không hoạt động trên GAE. Vì vậy, nếu chúng ta làm HTTP GET trên một số url khác nói url2 mà hiện HTTP GET trên url đầu tiên? Điều này dường như hoạt động trong GAE. Mã cho cái này trông như thế này

 
class FirstUrl(webapp.RequestHandler): 
    def get(self): 
     self.response.out.write("ok") 
     time.sleep(2) 
     urlfetch.fetch("http://"+self.request.headers["HOST"]+'/url2') 

class SecondUrl(webapp.RequestHandler): 
    def get(self): 
     self.response.out.write("ok") 
     time.sleep(2) 
     urlfetch.fetch("http://"+self.request.headers["HOST"]+'/url1') 

application = webapp.WSGIApplication([('/url1', FirstUrl), ('/url2', SecondUrl)]) 
def main(): 
    run_wsgi_app(application) 
if __name__ == "__main__": 
    main() 

Vì chúng tôi đã tìm ra cách để chạy tác vụ nền, cho phép xây dựng trừu tượng cho công việc định kỳ (hẹn giờ) và cấu trúc vòng lặp trải rộng trên nhiều yêu cầu HTTP (foreach).

Hẹn giờ
Giờ xây dựng ngay lập tức. Ý tưởng cơ bản là có danh sách các bộ đếm thời gian và khoảng thời gian mà mỗi cái sẽ được gọi. Khi chúng tôi đạt đến khoảng thời gian đó, hãy gọi hàm gọi lại. Chúng tôi sẽ sử dụng memcache để duy trì danh sách hẹn giờ. Để tìm hiểu khi nào gọi lại gọi lại, chúng tôi sẽ lưu trữ một khóa trong memcache với khoảng thời gian hết hạn. Chúng tôi định kỳ (nói 5 giây) kiểm tra xem khóa đó có hiện diện không, nếu không có thì gọi lại cuộc gọi và đặt lại khóa đó với khoảng thời gian.

 
def timer(func, interval): 
    timerlist = memcache.get('timer') 
    if(None == timerlist): 
     timerlist = [] 
    timerlist.append({'func':func, 'interval':interval}) 
    memcache.set('timer-'+func, '1', interval) 
    memcache.set('timer', timerlist) 

def checktimers(): 
    timerlist = memcache.get('timer') 
    if(None == timerlist): 
     return False 
    for current in timerlist: 
     if(None == memcache.get('timer-'+current['func'])): 
      #reset interval 
      memcache.set('timer-'+current['func'], '1', current['interval']) 
      #invoke callback function 
      try: 
       eval(current['func']+'()') 
      except: 
       pass 
      return True 
    return False 

Foreach
này là cần thiết khi chúng ta muốn làm tính toán lấy dài nói làm một số hoạt động trên 1000 hàng cơ sở dữ liệu hoặc lấy 1000 url vv Ý tưởng cơ bản là để duy trì danh sách các callbacks và lập luận trong memcache và mỗi lần gọi gọi lại với đối số.

 
def foreach(func, args): 
    looplist = memcache.get('foreach') 
    if(None == looplist): 
     looplist = [] 
    looplist.append({'func':func, 'args':args}) 
    memcache.set('foreach', looplist) 

def checkloops(): 
    looplist = memcache.get('foreach') 
    if(None == looplist): 
     return False 
    if((len(looplist) > 0) and (len(looplist[0]['args']) > 0)): 
     arg = looplist[0]['args'].pop(0) 
     func = looplist[0]['func'] 
     if(len(looplist[0]['args']) == 0): 
      looplist.pop(0) 
     if((len(looplist) > 0) and (len(looplist[0]['args']) > 0)): 
      memcache.set('foreach', looplist) 
     else: 
      memcache.delete('foreach') 
     try: 
      eval(func+'('+repr(arg)+')') 
     except: 
      pass 
     return True 
    else: 
     return False 

# instead of 
# foreach index in range(0, 1000): 
# someoperaton(index) 
# we will say 
# foreach('someoperaton', range(0, 1000)) 

Bây giờ, hãy tạo một chương trình tìm nạp danh sách url mỗi một giờ về phía trước. Đây là mã.

 
def getone(url): 
    try: 
     result = urlfetch.fetch(url) 
     if(result.status_code == 200): 
      memcache.set(url, '1', 60*60) 
      #process result.content 
    except : 
     pass 

def getallurl(): 
    #list of urls to be fetched 
    urllist = ['http://www.google.com/', 'http://www.cnn.com/', 'http://www.yahoo.com', 'http://news.google.com'] 
    fetchlist = [] 
    for url in urllist: 
     if (memcache.get(url) is None): 
      fetchlist.append(url) 
    #this is equivalent to 
    #for url in fetchlist: getone(url) 
    if(len(fetchlist) > 0): 
     foreach('getone', fetchlist) 

#register the timer callback 
timer('getallurl', 3*60) 

mã hoàn chỉnh là ở đây http://groups.google.com/group/httpmr-discuss/t/1648611a54c01aa Tôi đã được chạy mã này vào appengine cho vài ngày mà không có nhiều vấn đề.

Cảnh báo: Chúng tôi sử dụng nhiều urlfetch. Giới hạn không có urlfetch mỗi ngày là 160000. Vì vậy, hãy cẩn thận để không đạt đến giới hạn đó.

+0

tuyệt vời! Tôi thích nó – fuentesjr

+0

Tôi không thấy nó có thể hoạt động như thế nào. Bạn sẽ không vượt quá 10 giây hạn ngạch trên lần tìm nạp đệ quy thứ 6? – Constantin

+1

Đúng nếu tôi sai, không có chính sách AppEngine về liên lạc giữa các ứng dụng được lưu trữ không? – zotherstupidguy

2

Phiên bản thời gian chạy sắp tới sẽ có một số loại động cơ thực thi định kỳ a'la cron. Xem this message trên nhóm AppEngine.

Vì vậy, tất cả các phần SDK dường như hoạt động, nhưng thử nghiệm của tôi cho biết điều này hiện không chạy trên máy chủ sản xuất-- Tôi thiết lập cron "cứ 1 phút" khi nhật ký chạy và chưa được gọi là chưa

Khó nói khi điều này sẽ có sẵn, mặc dù ...

4

Bạn có thể tìm thêm về cron jobs trong Python App Engine here.

1

Sử dụng Deferred Python Library là cách dễ nhất để làm nhiệm vụ cơ bản về AppEngine sử dụng Python được xây dựng trên đầu trang của hàng tác vụ API.

from google.appengine.ext import deferred 

def do_something_expensive(a, b, c=None): 
    logging.info("Doing something expensive!") 
    # Do your work here 

# Somewhere else 
deferred.defer(do_something_expensive, "Hello, world!", 42, c=True) 
+0

Có những ưu điểm và nhược điểm khi sử dụng thư viện hoãn lại, xem phần "Khi nào sử dụng ext.deferred" trong bài viết của Nick Johnson: https://cloud.google.com/appengine/articles/deferred?hl=vi –

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