0

GZipped LXMLファイルをフェッチして、ProductエントリをDatabseモデルに書き込もうとしています。以前、私はローカルメモリの問題を抱えていましたが、SOのヘルプによって解決されました(質問)。これですべてが機能し、デプロイされましたが、サーバーで次のエラーが発生します。

Exceeded soft private memory limit with 158.164 MB after servicing 0 requests total

今、私はメモリ使用量を減らすために私が知っているすべてを試し、現在以下のコードを使用しています。Gzip圧縮されたファイルは約7MBですが、解凍されたファイルは80MBです。ローカルでは、コードは正常に機能しています。Cron Jobと同様にHTTPリクエストとして実行してみましたが、違いはありませんでした。今、私はそれをより効率的にする方法があるかどうか疑問に思っています。

SOに関するいくつかの同様の質問は、私がよく知らないフロントエンドとバックエンドの仕様に言及していました。私はGAEの無料バージョンを実行していますが、このタスクは週に1回実行する必要があります。前進するための最善の方法に関する提案をいただければ幸いです。

from google.appengine.api.urlfetch import fetch
import gzip, base64, StringIO, datetime, webapp2
from lxml import etree
from google.appengine.ext import db

class GetProductCatalog(webapp2.RequestHandler):
  def get(self):
    user = XXX
    password = YYY
    url = 'URL'

    # fetch gziped file
    catalogResponse = fetch(url, headers={
        "Authorization": "Basic %s" % base64.b64encode(user + ':' + password)
    }, deadline=10000000)

    # the response content is in catalogResponse.content
    # un gzip the file
    f = StringIO.StringIO(catalogResponse.content)
    c = gzip.GzipFile(fileobj=f)
    content = c.read()

    # create something readable by lxml
    xml = StringIO.StringIO(content)

    # delete unnecesary variables
    del f
    del c
    del content

    # parse the file
    tree = etree.iterparse(xml, tag='product')

    for event, element in tree:
        if element.findtext('manufacturer') == 'New York':
            if Product.get_by_key_name(element.findtext('sku')):
                    coupon = Product.get_by_key_name(element.findtext('sku'))
                    if coupon.last_update_prov != datetime.datetime.strptime(element.findtext('lastupdated'), "%d/%m/%Y"):
                        coupon.restaurant_name = element.findtext('name')
                        coupon.restaurant_id = ''
                        coupon.address_street = element.findtext('keywords').split(',')[0]
                        coupon.address_city = element.findtext('manufacturer')
                        coupon.address_state = element.findtext('publisher')
                        coupon.address_zip = element.findtext('manufacturerid')
                        coupon.value = '$' + element.findtext('price') + ' for $' + element.findtext('retailprice')
                        coupon.restrictions = element.findtext('warranty')
                        coupon.url = element.findtext('buyurl')
                        if element.findtext('instock') == 'YES':
                            coupon.active = True
                        else:
                            coupon.active = False
                        coupon.last_update_prov = datetime.datetime.strptime(element.findtext('lastupdated'), "%d/%m/%Y")
                        coupon.put()
                    else:
                        pass
            else:
                    coupon = Product(key_name = element.findtext('sku'))
                    coupon.restaurant_name = element.findtext('name')
                    coupon.restaurant_id = ''
                    coupon.address_street = element.findtext('keywords').split(',')[0]
                    coupon.address_city = element.findtext('manufacturer')
                    coupon.address_state = element.findtext('publisher')
                    coupon.address_zip = element.findtext('manufacturerid')
                    coupon.value = '$' + element.findtext('price') + ' for $' + element.findtext('retailprice')
                    coupon.restrictions = element.findtext('warranty')
                    coupon.url = element.findtext('buyurl')
                    if element.findtext('instock') == 'YES':
                        coupon.active = True
                    else:
                        coupon.active = False

                    coupon.last_update_prov = datetime.datetime.strptime(element.findtext('lastupdated'), "%d/%m/%Y")
                    coupon.put()
        else:
            pass

        element.clear()

UDPATE

Paulの提案によると、私はバックエンドを実装しました。いくつかのトラブルの後、それは魅力のように機能しました-私が以下で使用したコードを見つけてください。

私のbackends.yamlは次のようになります:

backends:
- name: mybackend
  instances: 10
  start: mybackend.app
  options: dynamic

そして私のapp.yamlは次のとおりです:

handlers:
- url: /update/mybackend
  script: mybackend.app
  login: admin
4

2 に答える 2

2

バックエンドはフロントエンドインスタンスに似ていますが、拡張性がなく、必要に応じて停止および開始する必要があります(または、動的に設定する必要があります。おそらくここで最善の策です)。

バックエンドには最大1024MBのメモリを搭載できるため、タスクで問題なく動作する可能性があります。

https://developers.google.com/appengine/docs/python/backends/overview

App Engineバックエンドは、リクエストの期限が免除され、通常のインスタンスよりも多くのメモリ(最大1GB)とCPU(最大4.8GHz)にアクセスできるアプリケーションのインスタンスです。これらは、より高速なパフォーマンス、大量のアドレス指定可能なメモリ、および継続的または長時間実行されるバックグラウンドプロセスを必要とするアプリケーション向けに設計されています。バックエンドにはいくつかのサイズと構成があり、CPU使用率ではなく稼働時間に対して請求されます。

バックエンドは、常駐または動的として構成できます。常駐バックエンドは継続的に実行されるため、時間の経過に伴うメモリの状態に依存して、複雑な初期化を実行できます。動的バックエンドは、リクエストを受信すると発生し、アイドル状態になるとオフになります。これらは、断続的またはユーザーアクティビティによって駆動される作業に最適です。常駐バックエンドと動的バックエンドの違いの詳細については、「バックエンドの種類」および「起動とシャットダウン」の説明を参照してください。

それはあなたが必要としているもののように聞こえます。無料の使用レベルもあなたのタスクにOKです。

于 2013-02-22T12:24:58.490 に答える
0

バックエンドについて: あなたが提供した例を見ると、あなたのリクエストは単にフロントエンド インスタンスによって処理されているようです。

バックエンドによって処理されるようにするには、代わりに次のようなタスクを呼び出してみてください: http://mybackend.my_app_app_id.appspot.com/update/mybackend

また、次を削除できると思いますstart: mybackend.app:backends.yaml

于 2013-02-22T13:33:17.733 に答える