Google App Engine y Google Sheets superan el límite de memoria blanda

Estoy escribiendo un servicio simple para tomar datos de un par de fonts, mezclarlo y usar el cliente API de Google para enviarlo a una hoja de Google. Easy peasy funciona bien, los datos no son tan grandes.

El problema es que llamar a .spreadsheets () después de comstackr el servicio de api (es decir, build('sheets', 'v4', http=auth).spreadsheets() ) provoca un salto de memoria de aproximadamente 30 megabytes (hice algunos perfiles para separar donde se estaba asignando la memoria). Cuando se implementan en GAE, estos picos se mantienen durante largos períodos de tiempo (a veces, horas a la vez), avanzan lentamente y, después de varias solicitudes, se genera el error de “Límite de memoria privada suave excedida” de GAE.

Estoy usando memcache para el documento de descubrimiento y urlfetch para capturar datos, pero esos son los únicos otros servicios que estoy usando.

He intentado la recolección manual de basura, cambiando la seguridad de subprocesos en app.yaml, incluso cosas como cambiar el punto en el que se llama a .spreadsheets () y no puedo evitar este problema. También es posible que simplemente esté malinterpretando algo sobre la architecture de GAE, pero sé que el aumento se debe a la llamada a .spreadsheets () y no estoy almacenando nada en cachés locales.

¿Hay alguna manera de 1) reducir el tamaño del pico de memoria al llamar a .spreadsheets () o 2) evitar que los picos permanezcan en la memoria (o preferiblemente hacer ambos). A continuación, se encuentra un resumen muy simplificado para dar una idea de las llamadas a la API y del manejador de solicitudes. Puedo dar un código más completo si es necesario. Sé que preguntas similares se han hecho antes, pero no puedo solucionarlo.

https://gist.github.com/chill17/18f1caa897e6a20201232165aca05239

Me encontré con esto cuando utilizaba la API de hojas de cálculo en un procesador pequeño con solo 20 MB de RAM utilizable. El problema es que el cliente API de Google extrae toda la API en formato de cadena y la almacena como un objeto de recurso en la memoria.

Si la memoria libre es un problema, debe crear su propio objeto http y realizar manualmente la solicitud deseada. Vea mi clase de Hoja de cálculo () como un ejemplo de cómo crear una nueva hoja de cálculo usando este método.

 SCOPES = 'https://www.googleapis.com/auth/spreadsheets' CLIENT_SECRET_FILE = 'client_secret.json' APPLICATION_NAME = 'Google Sheets API Python Quickstart' class Spreadsheet: def __init__(self, title): #Get credentials from locally stored JSON file #If file does not exist, create it self.credentials = self.getCredentials() #HTTP service that will be used to push/pull data self.service = httplib2.Http() self.service = self.credentials.authorize(self.service) self.headers = {'content-type': 'application/json', 'accept-encoding': 'gzip, deflate', 'accept': 'application/json', 'user-agent': 'google-api-python-client/1.6.2 (gzip)'} print("CREDENTIALS: "+str(self.credentials)) self.baseUrl = "https://sheets.googleapis.com/v4/spreadsheets" self.spreadsheetInfo = self.create(title) self.spreadsheetId = self.spreadsheetInfo['spreadsheetId'] def getCredentials(self): """Gets valid user credentials from storage. If nothing has been stored, or if the stored credentials are invalid, the OAuth2 flow is completed to obtain the new credentials. Returns: Credentials, the obtained credential. """ home_dir = os.path.expanduser('~') credential_dir = os.path.join(home_dir, '.credentials') if not os.path.exists(credential_dir): os.makedirs(credential_dir) credential_path = os.path.join(credential_dir, 'sheets.googleapis.com-python-quickstart.json') store = Storage(credential_path) credentials = store.get() if not credentials or credentials.invalid: flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES) flow.user_agent = APPLICATION_NAME if flags: credentials = tools.run_flow(flow, store, flags) else: # Needed only for compatibility with Python 2.6 credentials = tools.run(flow, store) print('Storing credentials to ' + credential_path) return credentials def create(self, title): #Only put title in request body... We don't need anything else for now requestBody = { "properties":{ "title":title }, } print("BODY: "+str(requestBody)) url = self.baseUrl response, content = self.service.request(url, method="POST", headers=self.headers, body=str(requestBody)) print("\n\nRESPONSE\n"+str(response)) print("\n\nCONTENT\n"+str(content)) return json.loads(content)