開始使用:工作佇列

瞭解如何使用工作佇列及 App Engine Image API 調整圖片大小。

工作佇列可以在直接的使用者互動之外執行程式碼,允許工作在背景中執行。本指南說明如何使用工作佇列,在將圖片新增至 Cloud Storage 之後執行工作。下列為工作佇列中所要執行的工作:

  1. 擷取剛才上傳至 Cloud Storage 的圖片。
  2. 使用 Image API 將圖片大小調整為縮圖圖片。
  3. 將完成的圖片儲存至 Cloud Storage。

App Engine Java 8 執行階段也支援使用 Java 的原生圖片操縱類別,例如 AWTJava2D

事前準備

  1. 設定開發環境及建立 App Engine 專案

  2. 本指南使用 Apache Commons IOUtils 程式庫。若要將 IOUtils 程式庫加入您的 App Engine 專案:

    新增至 pom.xml

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.5</version>
    </dependency>
    

匯入程式庫

本指南提供的範例程式碼使用下列匯入功能:

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;

建立工作佇列

雖然 App Engine 提供 default 工作佇列,但您可以為不同類型的工作建立不同的工作佇列。舉例來說,您可以建立一個工作佇列來調整圖片大小,另一個則用於更新應用程式資料庫。

如要新增佇列,請在 App Engine 專案的 WEB-INF 目錄中建立 queue.xml 檔案。工作佇列必須指定名稱和執行速率:

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

這個範例佇列名為 resize-image,定義執行速率為每小時 60 次或每分鐘 1 次。如要查看完整的清單佇列選項,請參閱 queue.xml 參考資料

工作佇列有兩個元件:工作要求者和工作處理常式。要求者可以將工作新增至佇列,並傳送工作給工作處理常式。

將工作新增至佇列

如要將工作加入佇列:

  1. 使用 QueueFactory.getQueue() 建立工作佇列物件,確認您指定了 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. 將工作新增至 Queue 物件。如同程式碼範例所示,imageResizeQueue.add() 會將工作新增至 imageResizeQueue 物件:

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

    使用 TaskOptions.Builder.withUrl() 以及任何傳送至處理常式的參數,以指定工作處理常式的 URI。

    在此範例中,URI 為 /tasks/imageresize,參數則是名稱為 filename 的變數,其中包含待處理圖片的檔案名稱。

建立工作處理常式

將工作加入佇列之後,對應到 URI /tasks/imageresize 的工作處理常式便會執行。工作處理常式為 Java Servlet,其會嘗試執行工作直到成功為止。

在本範例中,工作處理常式會執行三項工作:

  • 從 Cloud Storage 中擷取呼叫者指定的圖片。

  • 使用 App Engine Image API 轉換圖片,在本範例中為縮圖圖片。

  • 將已完成轉換的圖片 (縮圖) 儲存至 Cloud Storage。

如要建立工作處理常式:

  1. 新增可將處理常式對應至 URI /tasks/imageresize 的註解:

     @WebServlet(name = "imageResize", description = "Task queue handler", urlPatterns = "/tasks/imageresize")
     public class imageResize extends HttpServlet {
    
       // Task handler functionality
    
     }
    
  2. 依照 Cloud Storage 使用指南的說明,設定連線至 Cloud Storage,並從 Cloud Storage 中擷取圖片:

     public void init() throws ServletException {
    
      // initiate GcsService
      GcsService gcsService =
        GcsServiceFactory.createGcsService(
            new RetryParams.Builder()
                .initialRetryDelayMillis(10)
                .retryMaxAttempts(10)
                .totalRetryPeriodMillis(15000)
                .build());
    }
    
  3. 處理傳入的工作佇列要求,使用提供的檔案名稱從 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. 使用 ImagesService 物件調整圖片大小:

    // 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()));
    

    上方程式碼片段採用 Image API makeResize() 方法將圖片的大小調整為縮圖。為此,程式碼片段會將 Cloud Storage 內的圖片讀入 InputChannel,然後透過 IOUtils.toByteArray() 將圖片轉換成 ByteArray。

    套用轉換之後,新圖片的檔案名稱會附加上字串 thumbnail_,且權限設定為可公開讀取,並寫入 Cloud Storage。

保護工作處理常式網址

您應該保護執行機密作業的工作 (例如資料修改),以便讓外部使用者無法直接呼叫該工作。如要執行保護措施,您可以設定僅限 App Engine 管理員存取工作,這樣能防止使用者存取工作網址。請注意,這項限制不會套用至來自 App Engine 應用程式的工作要求。

在目前的範例中,工作處理常式在 /tasks/ 資料夾中擁有網址。如要設定僅限 App Engine 管理員存取 /tasks/ 資料夾,請將以下內容新增到專案的 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>

移除佇列中的單項工作

如要從佇列中移除單項工作,請使用 deleteTask()

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

移除佇列中的所有工作

如要從佇列中移除所有工作,請使用 purge()。清除作業可能需要一分鐘才能移除佇列中的所有工作。

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

由於從佇列中刪除所有工作可能需要一分鐘的時間,因此您應該先等候幾秒鐘,然後再將新工作新增到佇列。

刪除工作佇列

如要刪除工作佇列,請從專案的 queue.xml 檔案中移除項目,然後重新部署。

部署至 App Engine

您可以透過 Maven 將應用程式部署至 App Engine。

請前往專案的根目錄,並輸入以下內容:

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

PROJECT_ID 替換為您的 Google Cloud 專案 ID。如果 pom.xml 檔案已指定專案 ID,您就不需要在執行的指令中加入 -Dapp.deploy.projectId 屬性。

請在 Maven 部署應用程式後輸入下列指令,以便在新的應用程式中自動開啟網路瀏覽器分頁:

gcloud app browse

後續步驟

本指南說明如何透過工作佇列建立圖片縮圖,並將其儲存至 Cloud Storage。工作佇列也可以與 Cloud DatastoreCloud SQL 等其他儲存空間服務搭配使用。