3
\$\begingroup\$

I made a wrapper for an API that I am using, basically what I'm doing is sending in a list of Series objects and for each item in the list, a thread ("worker"?) starts and fetches information for their respective series.

The API that I'm using doesn't support fetching several series using one request, which would simplify this by a large margin, therefore I run threads for each item in the list.

I'm mostly concerned about the thread part, but I'll provide all the other parts as well.

@RequestMapping(value = "/series", method = RequestMethod.POST)
public List<Response> fetchSeveralSeries(@RequestBody List<Series> list) throws InterruptedException, ExecutionException {
    List<Callable<Response>> callableList = new ArrayList<>();
    for (int i = 0; i < list.size(); i++) {
        callableList.add(new performRequest(list.get(i).getSeries()));
    }

    final ExecutorService service = Executors.newFixedThreadPool(list.size());
    List<Future<Response>> futureObjects = service.invokeAll(callableList);
    List<Response> series = new ArrayList<>();

    for (Future<Response> obj : futureObjects) {
        series.add(obj.get());
    }

    return series;
}

Callable class used. (temporarily in my Spring boot controller class, as my entire implementation is in the controller atm.)

private class performRequest implements Callable<Response> {
    private int seriesId;

    private performRequest(int seriesId) {
        this.seriesId = seriesId;
    }

    @Override
    public Response call() throws UnirestException {
        return request.send(new Url(seriesId).toString());
    }
}

About the request made by each thread, I have a Url class which constructs the Url for the request and a Request class which sends the request to the external API.

Request class which sends the request to external API. The Response object is a "GSON Object".

@Service
public class Request {

    private static final Logger logger = LoggerFactory.getLogger(Request.class);

    public Response send(String url) throws UnirestException {
        logger.info("sending GET");
        HttpResponse<JsonNode> json = Unirest.get(url).asJson();
        String body = json.getBody().toString();
        return new Gson().fromJson(body, Response.class);
    }

}

Url class which constructs the URL.

@Data
public class Url {
    private static final String BASE_URL = "https://api.themoviedb.org/3";
    private static final String API_KEY = System.getenv("API_KEY");

    private Integer id;
    private Integer season;
    private Integer episode;
    private String searchQuery; // should turn spaces into %20

    public Url(String searchQuery) {
        this.searchQuery = searchQuery;
    }

    public Url(Integer id) {
        this.id = id;
    }

    public Url(Integer id, Integer season) {
        this.id = id;
        this.season = season;
    }

    public Url(Integer id, Integer season, Integer episode) {
        this.id = id;
        this.season = season;
        this.episode = episode;
    }

    @Override
    public String toString() {
        return this.searchQuery != null ?
                String.format("%s/search/tv?api_key=%s&language=en-US&query=%s", BASE_URL, API_KEY, this.searchQuery) : this.episode != null ?
                String.format("%s/tv/%s/season/%s/episode/%s?api_key=%s&language=en-US", BASE_URL, this.id, this.season, this.episode, API_KEY) : this.season != null ?
                String.format("%s/tv/%s/season/%s?api_key=%s&language=en-US", BASE_URL, this.id, this.season, API_KEY) :
                String.format("%s/tv/%s?api_key=%s&language=en-US", BASE_URL, this.id, API_KEY);
    }

}

An example POST request body would be something like below:

[
    {
        "series": 37680
    },
    {
        "series": 53123
    },
    {
        "series": 12345
    },
    {
        "series": 29182
    }
]

Could my code be improved somehow? Would it be possible to decrease response time? Is it "thread-safe"?
Any feedback is welcome.

\$\endgroup\$
1
\$\begingroup\$

Consider following point:

  1. For Request.send() is thread safe as it does not used any sharing resource of Request class.
  2. As per provided code single(singleton) object will be created as per default spring configuration.

  3. You must shutdown ExecutorService once no more thread need to be add.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy