161 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright (C) 2010 Google Inc.
 | 
						|
#
 | 
						|
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
# you may not use this file except in compliance with the License.
 | 
						|
# You may obtain a copy of the License at
 | 
						|
#
 | 
						|
#      http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
# Unless required by applicable law or agreed to in writing, software
 | 
						|
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
# See the License for the specific language governing permissions and
 | 
						|
# limitations under the License.
 | 
						|
"""Sample for threading and queues.
 | 
						|
 | 
						|
A simple sample that processes many requests by constructing a threadpool and
 | 
						|
passing client requests by a thread queue to be processed.
 | 
						|
"""
 | 
						|
from apiclient.discovery import build
 | 
						|
from apiclient.errors import HttpError
 | 
						|
from oauth2client.file import Storage
 | 
						|
from oauth2client.client import OAuth2WebServerFlow
 | 
						|
from oauth2client.tools import run
 | 
						|
 | 
						|
import Queue
 | 
						|
import gflags
 | 
						|
import httplib2
 | 
						|
import logging
 | 
						|
import sys
 | 
						|
import threading
 | 
						|
import time
 | 
						|
 | 
						|
# How many threads to start.
 | 
						|
NUM_THREADS = 3
 | 
						|
 | 
						|
# A list of URLs to shorten.
 | 
						|
BULK = [
 | 
						|
    "https://code.google.com/apis/buzz/",
 | 
						|
    "https://code.google.com/apis/moderator/",
 | 
						|
    "https://code.google.com/apis/latitude/",
 | 
						|
    "https://code.google.com/apis/urlshortener/",
 | 
						|
    "https://code.google.com/apis/customsearch/",
 | 
						|
    "https://code.google.com/apis/shopping/search/",
 | 
						|
    "https://code.google.com/apis/predict",
 | 
						|
    "https://code.google.com/more",
 | 
						|
    ]
 | 
						|
 | 
						|
FLAGS = gflags.FLAGS
 | 
						|
FLOW = OAuth2WebServerFlow(
 | 
						|
    client_id='433807057907.apps.googleusercontent.com',
 | 
						|
    client_secret='jigtZpMApkRxncxikFpR+SFg',
 | 
						|
    scope='https://www.googleapis.com/auth/urlshortener',
 | 
						|
    user_agent='urlshortener-cmdline-sample/1.0')
 | 
						|
 | 
						|
gflags.DEFINE_enum('logging_level', 'ERROR',
 | 
						|
    ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
 | 
						|
    'Set the level of logging detail.')
 | 
						|
 | 
						|
queue = Queue.Queue()
 | 
						|
 | 
						|
 | 
						|
class Backoff:
 | 
						|
  """Exponential Backoff
 | 
						|
 | 
						|
  Implements an exponential backoff algorithm.
 | 
						|
  Instantiate and call loop() each time through
 | 
						|
  the loop, and each time a request fails call
 | 
						|
  fail() which will delay an appropriate amount
 | 
						|
  of time.
 | 
						|
  """
 | 
						|
 | 
						|
  def __init__(self, maxretries=8):
 | 
						|
    self.retry = 0
 | 
						|
    self.maxretries = maxretries
 | 
						|
    self.first = True
 | 
						|
 | 
						|
  def loop(self):
 | 
						|
    if self.first:
 | 
						|
      self.first = False
 | 
						|
      return True
 | 
						|
    else:
 | 
						|
      return self.retry < self.maxretries
 | 
						|
 | 
						|
  def fail(self):
 | 
						|
    self.retry += 1
 | 
						|
    delay = 2 ** self.retry
 | 
						|
    time.sleep(delay)
 | 
						|
 | 
						|
 | 
						|
def start_threads(credentials):
 | 
						|
  """Create the thread pool to process the requests."""
 | 
						|
 | 
						|
  def process_requests(n):
 | 
						|
    http = httplib2.Http()
 | 
						|
    http = credentials.authorize(http)
 | 
						|
    loop = True
 | 
						|
 | 
						|
 | 
						|
    while loop:
 | 
						|
      request = queue.get()
 | 
						|
      backoff = Backoff()
 | 
						|
      while backoff.loop():
 | 
						|
        try:
 | 
						|
          response = request.execute(http)
 | 
						|
          print "Processed: %s in thread %d" % (response['id'], n)
 | 
						|
          break
 | 
						|
        except HttpError, e:
 | 
						|
          if e.resp.status in [402, 403, 408, 503, 504]:
 | 
						|
            print "Increasing backoff, got status code: %d" % e.resp.status
 | 
						|
            backoff.fail()
 | 
						|
        except Exception, e:
 | 
						|
          print "Unexpected error. Exiting." + str(e)
 | 
						|
          loop = False
 | 
						|
          break
 | 
						|
 | 
						|
      print "Completed request"
 | 
						|
      queue.task_done()
 | 
						|
 | 
						|
 | 
						|
  for i in range(NUM_THREADS):
 | 
						|
    t = threading.Thread(target=process_requests, args=[i])
 | 
						|
    t.daemon = True
 | 
						|
    t.start()
 | 
						|
 | 
						|
 | 
						|
def main(argv):
 | 
						|
  try:
 | 
						|
    argv = FLAGS(argv)
 | 
						|
  except gflags.FlagsError, e:
 | 
						|
    print '%s\\nUsage: %s ARGS\\n%s' % (e, argv[0], FLAGS)
 | 
						|
    sys.exit(1)
 | 
						|
 | 
						|
  logging.getLogger().setLevel(getattr(logging, FLAGS.logging_level))
 | 
						|
 | 
						|
  storage = Storage('threadqueue.dat')
 | 
						|
  credentials = storage.get()
 | 
						|
  if credentials is None or credentials.invalid == True:
 | 
						|
    credentials = run(FLOW, storage)
 | 
						|
 | 
						|
  start_threads(credentials)
 | 
						|
 | 
						|
  http = httplib2.Http()
 | 
						|
  http = credentials.authorize(http)
 | 
						|
 | 
						|
  service = build("urlshortener", "v1", http=http,
 | 
						|
            developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
 | 
						|
  shortener = service.url()
 | 
						|
 | 
						|
  for url in BULK:
 | 
						|
    body = {"longUrl": url }
 | 
						|
    shorten_request = shortener.insert(body=body)
 | 
						|
    print "Adding request to queue"
 | 
						|
    queue.put(shorten_request)
 | 
						|
 | 
						|
  # Wait for all the requests to finish
 | 
						|
  queue.join()
 | 
						|
 | 
						|
 | 
						|
if __name__ == "__main__":
 | 
						|
  main(sys.argv)
 |