'Can't call AppEngine Image API getServingUrl method when using SpringBoot stack

Our project needs to serve scaled images. AppEngine ImageApi has a wonderful method called getServingUrl. But this API is only accessible from AppEngine.

Problem

I've created a PoC project with SpringBoot and gradle for AppEngine. And whenever I call a simple endpoint that should call getServingUrl I get the following error:

Can’t make API call blobstore.CreateEncodedGoogleStorageKey in a thread that is neither the original request thread nor a thread created by ThreadManage

But when I do a similar setup that is based on Servlets, it works as expected.

SpringBoot Setup

Here is an example of some files from my setup. build.gradle:

;; https://github.com/GoogleCloudPlatform/app-gradle-plugin
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.cloud.tools:appengine-gradle-plugin:2.2.0'
    }
}

plugins {
    id 'org.springframework.boot' version '2.2.6.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

apply plugin: 'com.google.cloud.tools.appengine'  // App Engine tasks

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation "com.google.appengine:appengine-api-1.0-sdk:2.0.4"

    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

test {
    useJUnitPlatform()
}

appengine {  // App Engine tasks configuration
    deploy {   // deploy configuration
        projectId = 'GCLOUD_CONFIG' // delegate to project in gcloud config
        version = 'GCLOUD_CONFIG'   // delegate to gcloud to generate a version
    }
}

appengine/app.yml

runtime: java11

Controller

package com.example.demo.controller;

import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.ServingUrlOptions;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ImageController {

    @RequestMapping("/image-url")
    public ImageUrlDto hello(@RequestParam String bucket, @RequestParam String image) {
        ServingUrlOptions options = ServingUrlOptions.Builder
                .withGoogleStorageFileName(String.format("/gs/%s/%s", bucket, image));
        return new ImageUrlDto(ImagesServiceFactory.getImagesService().getServingUrl(options));
    }
}

class ImageUrlDto {
    String url;
    public ImageUrlDto(String url) {
        this.url = url;
    }
}

Question

Servlet setup is working correctly, but spring setup no. I've read that Image API is accessible only within AppEngine standart environemnt and request thread/ThreadManager spawned thread.

Am I missing something for that Spring setup? Probably that requires some another form of deployment or thread configuration in order to work with Image API?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source