Getting Started: Task Queues

Learn how to use task queues and the App Engine Image API to resize images.

Task queues execute code outside of direct user interaction, allowing tasks to happen in the background. This guide uses a Task Queue to perform tasks after adding an image to Cloud Storage . The tasks to be performed in the Task Queue are:

  1. Retrieve the image file that just got uploaded to Cloud Storage.
  2. Resize it to a thumbnail image using the Image API .
  3. Store the resulting thumbnail in Cloud Storage.

The App Engine Java 8 runtime also supports Java's native image manipulation classes such as AWT and Java2D .

Before you begin

  1. Configure your development environment and create your App Engine project .

  2. This guide uses the Apache Commons IOUtils library . To include the IOUtils library to your App Engine project:

    Add to your pom.xml :

     < dependency 
    >  
    < groupId>commons 
     - 
     io 
    < / 
     groupId 
    >  
    < artifactId>commons 
     - 
     io 
    < / 
     artifactId 
    >  
    < version>2 
     .5 
    < / 
     version 
    >
    < / 
     dependency 
    > 
    

Importing libraries

The sample code provided with this guide uses the following imports:

  import 
  
 com.google.appengine.api.images. Image 
 
 ; 
 import 
  
 com.google.appengine.api.images. ImagesService 
 
 ; 
 import 
  
 com.google.appengine.api.images. ImagesServiceFactory 
 
 ; 
 import 
  
 com.google.appengine.api.images. Transform 
 
 ; 
 import 
  
 org.apache.commons.io.IOUtils 
 ; 
 

Creating a task queue

While App Engine provides a default task queue, you can create different task queues for different types of work. For example, you can create one task queue to resize images and another to update your app's database.

To add queues, create the queue.xml file in your App Engine project's WEB-INF directory. A taskqueue must specify a name and an execution rate:

 < ? 
 xml 
  
 version 
 = 
 "1.0" 
  
 encoding 
 = 
 "UTF-8" 
 ? 
>  
< queue 
 - 
 entries 
>  
< queue 
>  
< name>resize 
 - 
 image 
< / 
 name 
>  
< rate>60 
 / 
 h 
< / 
 rate 
>  
< / 
 queue 
>  
< / 
 queue 
 - 
 entries 
> 

This example queue, named resize-image , defines a rate of execution of 60 times per hour, or once a minute. To see the full list queue options see the queue.xml reference .

A task queue has two components, the task requester and a task handler. The requestor adds a task to the queue and sends it to the task handler.

Adding tasks to a queue

To add a task to a queue:

  1. Create a task queue object using QueueFactory.getQueue() , making sure you specify the queue name defined in the queue.xml :

      Queue 
      
     imageResizeQueue 
     ; 
      
     // Taskqueue queue 
     @Override 
     public 
      
     void 
      
     init 
     () 
      
     throws 
      
     ServletException 
      
     { 
      
     // Setup Cloud Storage service 
      
     gcsService 
      
     = 
      
     GcsServiceFactory 
     . 
     createGcsService 
     ( 
      
     new 
      
     RetryParams 
     . 
     Builder 
     () 
      
     . 
     initialRetryDelayMillis 
     ( 
     10 
     ) 
      
     . 
     retryMaxAttempts 
     ( 
     10 
     ) 
      
     . 
     totalRetryPeriodMillis 
     ( 
     15000 
     ) 
      
     . 
     build 
     ()); 
      
     // Initialize the queue object with the specific queue 
      
     imageResizeQueue 
      
     = 
      
     QueueFactory 
     . 
     getQueue 
     ( 
     [ 
     QUEUE 
     - 
     NAME 
     ] 
     ); 
      
     // Cloud SQL connection setup 
      
     try 
      
     { 
      
     final 
      
     String 
      
     url 
      
     = 
      
     System 
     . 
     getProperty 
     ( 
     "cloudsql" 
     ); 
      
     // Cloud SQL server URI 
      
     try 
      
     { 
      
     conn 
      
     = 
      
     DriverManager 
     . 
     getConnection 
     ( 
     url 
     ); 
      
     // Connect to the database 
      
     Statement 
      
     createTable 
     ; 
      
     // SQL statement 
      
     // Batch SQL table creation commands 
      
     createTable 
     . 
     addBatch 
     ( 
     createContentTableSql 
     ); 
      
     createTable 
     . 
     addBatch 
     ( 
     createUserTableSql 
     ); 
      
     createTable 
     . 
     addBatch 
     ( 
     createImageTableSql 
     ); 
      
     createTable 
     . 
     addBatch 
     ( 
     createBlogPostImageTableSql 
     ); 
      
     conn 
     . 
     createTable 
     . 
     executeBatch 
     (); 
      
     // Execute batch 
      
     } 
      
     catch 
      
     ( 
     SQLException 
      
     e 
     ) 
      
     { 
      
     throw 
      
     new 
      
     ServletException 
     ( 
     "Unable to connect to Cloud SQL" 
     , 
      
     e 
     ); 
      
     } 
      
     } 
      
     finally 
      
     { 
      
     // Nothing really to do here. 
      
     } 
     } 
     
    
  2. Add tasks to Queue object. As shown in the code sample, imageResizeQueue.add() adds a task to the imageResizeQueue object:

      try 
      
     { 
      
     // Add a queued task to create a thumbnail of the uploaded image 
      
     imageResizeQueue 
     . 
     add 
     ( 
      
     TaskOptions 
     . 
     Builder 
     . 
     withUrl 
     ( 
     "/tasks/imageresize" 
     ). 
     param 
     ( 
     "filename" 
     , 
      
     filename 
     )); 
     } 
     
    

    Specify the URI of the task handler using TaskOptions.Builder.withUrl() , along with and any parameters sent to the handler.

    In this example, the URI is /tasks/imageresize and the parameter is a variable called filename that contains the filename of the image to be processed.

Creating a task handler

Once you have added a task to the queue, the task handler mapped to the URI /tasks/imageresize will run. A task handler is a Java Servlet that attempts to perform the task until it is successful.

In this example, the task handler does three tasks:

  • Retrieve the image specified by the caller from Cloud Storage.

  • Transform the image using the App Engine Image API, in this sample, to a thumbnail image.

  • Store the transformed image (thumbnail) in Cloud Storage.

To create the task handler:

  1. Add an annotation that maps the handler to the URI /tasks/imageresize :

       
     @WebServlet 
     ( 
     name 
      
     = 
      
     "imageResize" 
     , 
      
     description 
      
     = 
      
     "Task queue handler" 
     , 
      
     urlPatterns 
      
     = 
      
     "/tasks/imageresize" 
     ) 
      
     public 
      
     class 
     imageResize 
      
     extends 
      
     HttpServlet 
      
     { 
      
     // Task handler functionality 
      
     } 
     
    
  2. Set up a connection to Cloud Storage as documented in the Using Cloud Storage guide and retrieve the image from Cloud Storage:

       
     public 
      
     void 
      
     init 
     () 
      
     throws 
      
     ServletException 
      
     { 
      
     // initiate GcsService 
      
     GcsService 
      
     gcsService 
      
     = 
      
     GcsServiceFactory 
     . 
     createGcsService 
     ( 
      
     new 
      
     RetryParams 
     . 
     Builder 
     () 
      
     . 
     initialRetryDelayMillis 
     ( 
     10 
     ) 
      
     . 
     retryMaxAttempts 
     ( 
     10 
     ) 
      
     . 
     totalRetryPeriodMillis 
     ( 
     15000 
     ) 
      
     . 
     build 
     ()); 
     } 
     
    
  3. Handle the incoming Task Queue request, using the supplied file name to retrieve the image from Cloud Storage:

      protected 
      
     void 
      
     doPost 
     ( 
     HttpServletRequest 
      
     req 
     , 
      
     HttpServletResponse 
      
     resp 
     ) 
      
     throws 
      
     ServletException 
     , 
      
     IOException 
      
     { 
      
     String 
      
     filename 
      
     = 
      
     req 
     . 
     getParameter 
     ( 
     "filename" 
     ); 
      
     // Get the filename passed from the task requestor 
      
     GcsFilename 
      
     gcsFile 
      
     = 
      
     new 
      
     GcsFilename 
     ( 
     bucket 
     , 
      
     filename 
     ); 
      
     // Create a valid Cloud Storage filename 
      
     GcsInputChannel 
      
     readChannel 
      
     = 
      
     gcsService 
     . 
     openPrefetchingReadChannel 
     ( 
     gcsFile 
     , 
      
     0 
     , 
      
     BUFFER_SIZE 
     ); 
      
     // Read the file from Cloud Storage 
     
    
  4. Use the ImagesService object to do the image resizing:

      // Get an instance of the ImagesService we can use to transform images. 
     ImagesService 
      
     imagesService 
      
     = 
      
     ImagesServiceFactory 
     . 
     getImagesService 
     (); 
     // Make an image directly from a byte array, and transform it. 
     Image 
      
     image 
      
     = 
      
     ImagesServiceFactory 
     . 
     makeImage 
     ( 
     IOUtils 
     . 
     toByteArray 
     ( 
     Channels 
     . 
     newInputStream 
     ( 
     readChannel 
     ))); 
     Transform 
      
     resize 
      
     = 
      
     ImagesServiceFactory 
     . 
     makeResize 
     ( 
     100 
     , 
      
     50 
     ); 
      
     // resize image to 100x50 
     Image 
      
     resizedImage 
      
     = 
      
     imagesService 
     . 
     applyTransform 
     ( 
     resize 
     , 
      
     image 
     ); 
     // Write the transformed image back to a Cloud Storage object. 
     gcsService 
     . 
     createOrReplace 
     ( 
      
     new 
      
     GcsFilename 
     ( 
     bucket 
     , 
      
     "thumbnail_" 
      
     + 
      
     filename 
     ), 
      
     new 
      
     GcsFileOptions 
     . 
     Builder 
     (). 
     acl 
     ( 
     "public-read" 
     ). 
     build 
     (), 
      
     ByteBuffer 
     . 
     wrap 
     ( 
     resizedImage 
     . 
     getImageData 
     ())); 
     
    

    The above snippet uses the Image API makeResize() method to resize the image to a thumbnail. To do this, it reads the image from Cloud Storage into an InputChannel and convert it to a ByteArray using IOUtils.toByteArray() .

    After applying the transformation, the new image has the string thumbnail_ appended to its filename, permission set to be publicly readable and written to Cloud Storage.

Securing task handler URLs

You should secure tasks that perform sensitive operations such as modifying data so external users cannot call it directly. You can do this by restricting task access to App Engine administrators, which prevents users from accessing task URLs . Note that this restriction does not apply to task requests coming from your App Engine app.

In the current example, the task handlers have URLs in the /tasks/ folder. To restrict access to the /tasks/ folder to App Engine administrators, add the following to the project's web.xml .

 < security 
 - 
 constraint 
>  
< web 
 - 
 resource 
 - 
 collection 
>  
< web 
 - 
 resource 
 - 
 name>tasks 
< / 
 web 
 - 
 resource 
 - 
 name 
>  
< url 
 - 
 pattern 
> / 
 tasks 
 /*</ 
 url 
 - 
 pattern 
>  
< / 
 web 
 - 
 resource 
 - 
 collection 
>  
< auth 
 - 
 constraint 
>  
< role 
 - 
 name>admin 
< / 
 role 
 - 
 name 
>  
< / 
 auth 
 - 
 constraint 
>
< / 
 security 
 - 
 constraint 
> 

Removing a single task from a queue

To remove a single task from a queue, use deleteTask() :

  private 
  
 void 
  
 removeTask 
 ( 
 Queue 
  
 queue 
 , 
  
 String 
  
 taskName 
 ) 
  
 { 
  
 queue 
 . 
 deleteTask 
 ( 
 taskName 
 ); 
  
 // remove a task from a queue 
 } 
 

Removing all tasks from a queue

To remove all tasks from a queue, use purge() . The purge can take up to a minute to remove all tasks in the queue.

  private 
  
 void 
  
 purgeQueue 
 ( 
 Queue 
  
 queue 
 ) 
  
 { 
  
 queue 
 . 
 purge 
 (); 
  
 // remove all tasks from a queue 
 } 
 

It can take a minute to remove all tasks from a queue, so you should wait a few seconds before adding new tasks to the queue.

Deleting a task queue

To delete a task queue, remove the entry from the project's queue.xml file and redeploy.

Deploying to App Engine

You can deploy your app to App Engine using Maven.

Go to the root directory of your project and type:

mvn package appengine:deploy -Dapp.deploy.projectId= PROJECT_ID 

Replace PROJECT_ID with the ID of your Google Cloud project. If your pom.xml file already specifies your project ID , you don't need to include the -Dapp.deploy.projectId property in the command you run.

After Maven deploys your app, open a web browser tab automatically at your new app by typing:

  gcloud 
  
 app 
  
 browse 
 

What's next

This guide shows how to use a task queue to create an image thumbnail and store it in Cloud Storage. It can be used with other storage services such as Cloud Datastore or Cloud SQL .

Create a Mobile Website
View Site in Mobile | Classic
Share by: