Per iniziare: code di attività

Scopri come utilizzare le code di attività e l'API App Engine Image per ridimensionare le immagini.

Le code di attività eseguono il codice al di fuori dell'interazione diretta dell'utente, consentendo l'esecuzione delle attività in background. Questa guida utilizza una coda di attività per eseguire le attività dopo aver aggiunto un'immagine a Cloud Storage. Le attività da eseguire nella coda di attività sono:

  1. Recupera il file immagine appena caricato su Cloud Storage.
  2. Ridimensionala trasformandola in un'immagine in miniatura utilizzando l'API Image.
  3. Archivia la miniatura risultante in Cloud Storage.

Il runtime Java 8 di App Engine supporta anche le classi di manipolazione delle immagini native di Java come AWT e Java2D.

Prima di iniziare

  1. Configura l'ambiente di sviluppo e crea il tuo progetto App Engine.

  2. Questa guida utilizza la libreria IOUtils di Apache Commons. Per includere la libreria IOUtils nel tuo progetto App Engine:

    Aggiungi a pom.xml:

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

Importazione delle librerie

Il codice campione fornito con questa guida utilizza le seguenti importazioni:

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;

Creazione di una coda di attività

Sebbene App Engine fornisca una coda di attività default, puoi creare code di attività diverse per tipi di lavoro diversi. Ad esempio, puoi creare una coda di attività per ridimensionare le immagini e un'altra per aggiornare il database dell'app.

Per aggiungere code, crea il file queue.xml nella directory WEB-INF del tuo progetto App Engine. Una coda di attività deve specificare un nome e una frequenza di esecuzione:

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

Questa coda di esempio, denominata resize-image, definisce una frequenza di esecuzione di 60 volte all'ora o una volta al minuto. Per vedere l'elenco completo delle opzioni relative alla coda, consulta il riferimento queue.xml.

Una coda di attività ha due componenti: il richiedente dell'attività e un gestore delle attività. Il richiedente aggiunge un'attività alla coda e la invia al gestore delle attività.

Aggiunta di attività a una coda

Per aggiungere un'attività a una coda:

  1. Crea un oggetto coda di attività utilizzando QueueFactory.getQueue(), assicurandoti di specificare il nome della coda definito in 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. Aggiungi attività all'oggetto Queue. Come mostrato nell'esempio di codice, imageResizeQueue.add() aggiunge un'attività all'oggetto imageResizeQueue:

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

    Specifica l'URI del gestore delle attività utilizzando TaskOptions.Builder.withUrl(), insieme a eventuali parametri inviati al gestore.

    In questo esempio, l'URI è /tasks/imageresize e il parametro è una variabile denominata filename contenente il nome del file dell'immagine da elaborare.

Creazione di un gestore delle attività

Una volta aggiunta un'attività alla coda, verrà eseguito il gestore delle attività mappato all'URI /tasks/imageresize. Un gestore di attività è un servlet Java che tenta di eseguire l'attività fino all'esito positivo.

In questo esempio, il gestore delle attività svolge tre attività:

  • Recupera l'immagine specificata dal chiamante da Cloud Storage.

  • Trasforma l'immagine utilizzando l'API App Engine Image, in questo esempio, in un'immagine in miniatura.

  • Archivia l'immagine trasformata (miniatura) in Cloud Storage.

Per creare il gestore delle attività:

  1. Aggiungi un'annotazione che mappa il gestore all'URI /tasks/imageresize:

     @WebServlet(name = "imageResize", description = "Task queue handler", urlPatterns = "/tasks/imageresize")
     public class imageResize extends HttpServlet {
    
       // Task handler functionality
    
     }
    
  2. Configura una connessione a Cloud Storage come documentato nella Guida all'utilizzo di Cloud Storage e recupera l'immagine da Cloud Storage:

     public void init() throws ServletException {
    
      // initiate GcsService
      GcsService gcsService =
        GcsServiceFactory.createGcsService(
            new RetryParams.Builder()
                .initialRetryDelayMillis(10)
                .retryMaxAttempts(10)
                .totalRetryPeriodMillis(15000)
                .build());
    }
    
  3. Gestisci la richiesta della coda di attività in arrivo utilizzando il nome file fornito per recuperare l'immagine da 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. Utilizza l'oggetto ImagesService per eseguire il ridimensionamento dell'immagine:

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

    Lo snippet riportato sopra utilizza il metodo makeResize() dell'API Image per ridimensionare l'immagine in miniatura. Per farlo, legge l'immagine da Cloud Storage in un InputChannel e la converte in un ByteArray utilizzando IOUtils.toByteArray().

    Dopo aver applicato la trasformazione, alla nuova immagine viene aggiunta la stringa thumbnail_ al nome file e l'autorizzazione è impostata per essere leggibile pubblicamente e scritta in Cloud Storage.

Protezione degli URL dei gestori delle attività

Devi proteggere le attività che eseguono operazioni sensibili come la modifica dei dati in modo che gli utenti esterni non possano chiamarli direttamente. Puoi farlo limitando l'accesso alle attività agli amministratori di App Engine, impedendo così agli utenti di accedere agli URL delle attività . Tieni presente che questa limitazione non si applica alle richieste di attività provenienti dalla tua applicazione App Engine.

Nell'esempio attuale, i gestori delle attività hanno URL nella cartella /tasks/. Per limitare l'accesso alla cartella /tasks/ agli amministratori di App Engine, aggiungi quanto segue al web.xml del progetto.

<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>

Rimozione di una singola attività da una coda

Per rimuovere una singola attività da una coda, utilizza deleteTask():

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

Rimozione di tutte le attività da una coda

Per rimuovere tutte le attività da una coda, utilizza purge(). L'eliminazione definitiva può richiedere fino a un minuto per rimuovere tutte le attività in coda.

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

La rimozione di tutte le attività dalla coda può richiedere qualche minuto, perciò è consigliabile attendere alcuni secondi prima di aggiungere nuove attività alla coda.

Eliminazione di una coda di attività

Per eliminare una coda di attività, rimuovi la voce dal file queue.xml del progetto ed esegui di nuovo il deployment.

Deployment in App Engine

Puoi eseguire il deployment della tua applicazione in App Engine utilizzando Maven.

Vai alla directory principale del progetto e digita:

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

Sostituisci PROJECT_ID con l'ID del tuo progetto Google Cloud. Se il file pom.xml specifica già l'ID progetto, non è necessario includere la proprietà -Dapp.deploy.projectId nel comando che esegui.

Dopo che Maven ha eseguito il deployment dell'app, apri automaticamente una scheda del browser web nella nuova app digitando:

gcloud app browse

Passaggi successivi

Questa guida mostra come utilizzare una coda di attività per creare una miniatura dell'immagine e archiviarla in Cloud Storage. Può essere utilizzato con altri servizi di archiviazione come Cloud Datastore o Cloud SQL.