Syntax highlighter header

Tuesday, 3 August 2021

Using CompletableFuture in Java

 Recently I was exploring CompletableFuture in Java and trying to find correct use case for it. This is what I found.

We have a service which need to combine data from multiple http calls. We submit http requests to a ExecutorService for doing that. We have a deadline that our service need to return in 2 seconds. So we set a deadline or 1 second for all http calls to return the response. If some http call does not return by this time we return timeout for that resource. Following is the code:


import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class HttpClientTest4 {
	private static String apiKey="your_key_here";
	
	public static class RunnableRequest implements Runnable {
		String url;
		private CompletableFuture<String> cf;
				
		public RunnableRequest(String url, CompletableFuture<String> cf) {
			this.url = url;
			this.cf = cf;
		}
		
		@Override
		public void run() {
			try {
				//System.out.println("calling the task for movieId "+ url);
				CloseableHttpClient client = HttpClients.createDefault();
				HttpGet request = new HttpGet(url);
				CloseableHttpResponse response = client.execute(request);
				if(response.getStatusLine().getStatusCode()!=200) {
					cf.completeExceptionally(new RuntimeException("Issue getting response"));
					return;
				}
				String respString = EntityUtils.toString(response.getEntity());
				client.close();
				cf.complete(respString);
			} catch(IOException exp) {
				cf.completeExceptionally(exp);
			}
		}
		
	}
	
	public static class MyCompletebaleFuture<K,V> extends CompletableFuture<V> {
		K k;
		public MyCompletebaleFuture(K k) {
			super();
			this.k = k;
		}
		K getKey() {
			return k;
		}
	}

	public static void main(String[] args)  {

		ExecutorService executorSerivce = Executors.newFixedThreadPool(5);
		
		List<String> movieIds  = Arrays.asList("100","125","133","134","156","101","107","108","120","220","221","225","234","254","256");
		List<MyCompletebaleFuture<String,String>> futures = new ArrayList<>();
		for (String movieId : movieIds) {
			String url = "https://api.themoviedb.org/3/movie/"+movieId+"?api_key="+apiKey;
			MyCompletebaleFuture<String,String> cf = new MyCompletebaleFuture<>(movieId);
 			RunnableRequest req = new RunnableRequest(url, cf);			
			//System.out.println("submitting the task for movieId "+ movieId);			
			executorSerivce.submit(req);
			futures.add(cf);
		}
		
		ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
		Runnable timeoutTask = new Runnable() {
			@Override
			public void run() {
				RuntimeException re = new RuntimeException("Timeout");
				for (CompletableFuture<String> future : futures) {
					future.completeExceptionally(re);
				}				
			}			
		};
		ses.schedule(timeoutTask, 1500, TimeUnit.MILLISECONDS);
		
		for (MyCompletebaleFuture<String,String> future : futures) {
			String resp=null;
			Throwable failureCause=null;
			try {
				resp = future.get();
			} catch (InterruptedException e) {
				failureCause = e;
			} catch (ExecutionException e) {
				failureCause = e.getCause();
			}
			if(failureCause==null) {
				System.out.println("MovieID="+future.getKey() +" res="+resp);
			} else {
				System.out.println("MovieID="+future.getKey() + " exception="+failureCause.toString());
			}
		}
		executorSerivce.shutdown();
		ses.shutdown();
	}

}

For me the output was:


MovieID=100 res={"adult":false,"backdrop_path":"/tY6zVyt0OubPgCapbXFJLKhQqSu.jpg","belongs_to_collection":null,"budget":1350000,"genres":[{"id":35,"name":"Comedy"},{"id":80,"name":"Crime"}],"homepage":"http://www.universalstudiosentertainment.com/lock-stock-and-two-smoking-barrels/","id":100,"imdb_id":"tt0120735","original_language":"en","original_title":"Lock, Stock and Two Smoking Barrels","overview":"A card shark and his unwillingly-enlisted friends need to make a lot of cash quick after losing a sketchy poker match. To do this they decide to pull a heist on a small-time gang who happen to be operating out of the flat next door.","popularity":8.102,"poster_path":"/8kSerJrhrJWKLk1LViesGcnrUPE.jpg","production_companies":[{"id":491,"logo_path":"/rUp0lLKa1pr4UsPm8fgzmnNGxtq.png","name":"Summit Entertainment","origin_country":"US"},{"id":21920,"logo_path":null,"name":"The Steve Tisch Company","origin_country":""},{"id":13419,"logo_path":null,"name":"SKA Films","origin_country":""},{"id":1382,"logo_path":"/sOg7LGESPH5vCTOIdbMhLuypoLL.png","name":"PolyGram Filmed Entertainment","origin_country":"US"},{"id":20076,"logo_path":"/i9qXGJIP9fGN22PP5jXUVENbyHi.png","name":"HandMade Films","origin_country":"GB"}],"production_countries":[{"iso_3166_1":"GB","name":"United Kingdom"}],"release_date":"1998-03-05","revenue":28356188,"runtime":105,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Released","tagline":"A Disgrace to Criminals Everywhere.","title":"Lock, Stock and Two Smoking Barrels","video":false,"vote_average":8.2,"vote_count":4932}
MovieID=125 res={"adult":false,"backdrop_path":null,"belongs_to_collection":null,"budget":0,"genres":[{"id":99,"name":"Documentary"}],"homepage":"","id":125,"imdb_id":"tt0080668","original_language":"pl","original_title":"Dworzec","overview":"Kieslowski’s later film Dworzec (Station, 1980) portrays the atmosphere at Central Station in Warsaw after the rush hour.","popularity":1.94,"poster_path":"/c4xG9QoCx2zXc8iP3jQVLYDHiMi.jpg","production_companies":[{"id":2466,"logo_path":null,"name":"WFD","origin_country":""}],"production_countries":[{"iso_3166_1":"PL","name":"Poland"}],"release_date":"1980-01-01","revenue":0,"runtime":13,"spoken_languages":[{"english_name":"Polish","iso_639_1":"pl","name":"Polski"}],"status":"Released","tagline":"","title":"Railway Station","video":false,"vote_average":5.9,"vote_count":16}
MovieID=133 res={"adult":false,"backdrop_path":"/e6IPjjDzZDkgdkvxQtCjaVCMYJF.jpg","belongs_to_collection":null,"budget":0,"genres":[{"id":99,"name":"Documentary"}],"homepage":"","id":133,"imdb_id":"tt0054205","original_language":"en","original_title":"Primary","overview":"Primary is a documentary film about the primary elections between John F. Kennedy and Hubert Humphrey in 1960. Primary is the first documentary to use light equipment in order to follow their subjects in a more intimate filmmaking style. This unconventional way of filming created a new look for documentary films where the camera’s lens was right in the middle of what ever drama was occuring.","popularity":3.616,"poster_path":"/gVloWsthHRlw719vzRWRpBqDM20.jpg","production_companies":[{"id":2401,"logo_path":null,"name":"Drew Associates","origin_country":""},{"id":2402,"logo_path":null,"name":"Time","origin_country":""}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"release_date":"1960-01-01","revenue":0,"runtime":60,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Released","tagline":"","title":"Primary","video":false,"vote_average":6.5,"vote_count":24}
MovieID=134 res={"adult":false,"backdrop_path":"/rbsm633lnt3hKHEpk7FOt3dy82a.jpg","belongs_to_collection":null,"budget":26000000,"genres":[{"id":12,"name":"Adventure"},{"id":35,"name":"Comedy"},{"id":80,"name":"Crime"}],"homepage":"","id":134,"imdb_id":"tt0190590","original_language":"en","original_title":"O Brother, Where Art Thou?","overview":"In the deep south during the 1930s, three escaped convicts search for hidden treasure while a relentless lawman pursues them. On their journey they come across many comical characters and incredible situations. Based upon Homer's 'Odyssey'.","popularity":12.979,"poster_path":"/2YztYilviFCYcEtDAnrOstUWGie.jpg","production_companies":[{"id":2092,"logo_path":null,"name":"Mike Zoss Productions","origin_country":"US"},{"id":33,"logo_path":"/8lvHyhjr8oUKOOy2dKXoALWKdp0.png","name":"Universal Pictures","origin_country":"US"},{"id":9195,"logo_path":"/ou5BUbtulr6tIt699q6xJiEQTR9.png","name":"Touchstone Pictures","origin_country":"US"},{"id":10163,"logo_path":"/16KWBMmfPX0aJzDExDrPxSLj0Pg.png","name":"Working Title Films","origin_country":"GB"},{"id":694,"logo_path":"/5LEHONGkZBIoWvp1ygHOF8iyi1M.png","name":"StudioCanal","origin_country":"FR"}],"production_countries":[{"iso_3166_1":"FR","name":"France"},{"iso_3166_1":"GB","name":"United Kingdom"},{"iso_3166_1":"US","name":"United States of America"}],"release_date":"2000-08-30","revenue":71868327,"runtime":107,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Released","tagline":"They have a plan... but not a clue.","title":"O Brother, Where Art Thou?","video":false,"vote_average":7.3,"vote_count":3022}
MovieID=156 res={"adult":false,"backdrop_path":null,"belongs_to_collection":null,"budget":0,"genres":[{"id":35,"name":"Comedy"},{"id":18,"name":"Drama"},{"id":10749,"name":"Romance"}],"homepage":"","id":156,"imdb_id":"tt0329767","original_language":"da","original_title":"Wilbur begår selvmord","overview":"The strange comedy film of two close brothers; one, Wilbur, who wants to kill himself, and the other, Harbour, who tries to prevent this. When their father dies leaving them his bookstore they meet a woman who makes their lives a bit better yet with a bit more trouble as well.","popularity":3.117,"poster_path":"/f2nq2ZLqKPRaWb4HeOwxULKkSNk.jpg","production_companies":[{"id":223,"logo_path":"/b9Icqi8qGm7gJ6jVs8bauUo5N5Q.png","name":"Les Films du Losange","origin_country":"FR"},{"id":235,"logo_path":"/obOynoztBEhDNfHsDXBqOuQLAZk.png","name":"Nordisk Film","origin_country":"DK"},{"id":698,"logo_path":null,"name":"Scottish Screen","origin_country":""},{"id":758,"logo_path":"/fft3jrctrZNcgAxgN1w5Givtzip.png","name":"TV 2","origin_country":"DK"},{"id":980,"logo_path":null,"name":"The Glasgow Film Fund","origin_country":""}],"production_countries":[{"iso_3166_1":"DK","name":"Denmark"},{"iso_3166_1":"FR","name":"France"},{"iso_3166_1":"GB","name":"United Kingdom"},{"iso_3166_1":"SE","name":"Sweden"}],"release_date":"2002-11-08","revenue":0,"runtime":111,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Released","tagline":"Meet a man dying to live","title":"Wilbur Wants to Kill Himself","video":false,"vote_average":6.5,"vote_count":61}
MovieID=101 res={"adult":false,"backdrop_path":"/jRJrQ72VLyEnVsvwfep8Xjlvu8c.jpg","belongs_to_collection":null,"budget":16000000,"genres":[{"id":80,"name":"Crime"},{"id":18,"name":"Drama"},{"id":28,"name":"Action"}],"homepage":"","id":101,"imdb_id":"tt0110413","original_language":"en","original_title":"Léon: The Professional","overview":"Léon, the top hit man in New York, has earned a rep as an effective \"cleaner\". But when his next-door neighbors are wiped out by a loose-cannon DEA agent, he becomes the unwilling custodian of 12-year-old Mathilda. Before long, Mathilda's thoughts turn to revenge, and she considers following in Léon's footsteps.","popularity":37.287,"poster_path":"/wHqGb8J6tXBVwjqWooGMtNEjs2A.jpg","production_companies":[{"id":9,"logo_path":"/nda3dTUYdDrJ6rZqBpYvY865aDv.png","name":"Gaumont","origin_country":"FR"},{"id":66743,"logo_path":null,"name":"Les Films du Dauphin","origin_country":"FR"},{"id":5,"logo_path":"/71BqEFAF4V3qjjMPCpLuyJFB9A.png","name":"Columbia Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"},{"iso_3166_1":"FR","name":"France"}],"release_date":"1994-09-14","revenue":45284974,"runtime":111,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"},{"english_name":"French","iso_639_1":"fr","name":"Français"},{"english_name":"Italian","iso_639_1":"it","name":"Italiano"}],"status":"Released","tagline":"If you want a job done well, hire a professional.","title":"Léon: The Professional","video":false,"vote_average":8.3,"vote_count":11096}
MovieID=107 res={"adult":false,"backdrop_path":"/32V4uHVRU2fbDsQl1dsYsZm3uba.jpg","belongs_to_collection":null,"budget":10000000,"genres":[{"id":80,"name":"Crime"},{"id":35,"name":"Comedy"}],"homepage":"","id":107,"imdb_id":"tt0208092","original_language":"en","original_title":"Snatch","overview":"Unscrupulous boxing promoters, violent bookmakers, a Russian gangster, incompetent amateur robbers and supposedly Jewish jewelers fight to track down a priceless stolen diamond.","popularity":17.959,"poster_path":"/56mOJth6DJ6JhgoE2jtpilVqJO.jpg","production_companies":[{"id":3287,"logo_path":"/bz6GbCQQXGNE56LTW9dwgksW0Iw.png","name":"Screen Gems","origin_country":"US"},{"id":13419,"logo_path":null,"name":"SKA Films","origin_country":""},{"id":5,"logo_path":"/71BqEFAF4V3qjjMPCpLuyJFB9A.png","name":"Columbia Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"GB","name":"United Kingdom"},{"iso_3166_1":"US","name":"United States of America"}],"release_date":"2000-09-01","revenue":83557872,"runtime":104,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"},{"english_name":"Russian","iso_639_1":"ru","name":"Pусский"}],"status":"Released","tagline":"Stealin' stones and breakin' bones.","title":"Snatch","video":false,"vote_average":7.8,"vote_count":6747}
MovieID=108 res={"adult":false,"backdrop_path":"/s9rWmLANsVlSV4XmuC0IUcseGzO.jpg","belongs_to_collection":{"id":131,"name":"Three Colors Collection","poster_path":"/ph9rRSTG4xL8nubxNrK00VUMn5l.jpg","backdrop_path":"/AeHExfHIl70SZCea907KfEoSkfJ.jpg"},"budget":0,"genres":[{"id":18,"name":"Drama"}],"homepage":"","id":108,"imdb_id":"tt0108394","original_language":"fr","original_title":"Trois couleurs : Bleu","overview":"Julie is haunted by her grief after living through a tragic auto wreck that claimed the life of her composer husband and young daughter. Her initial reaction is to withdraw from her relationships, lock herself in her apartment and suppress her pain. But avoiding human interactions on the bustling streets of Paris proves impossible, and she eventually meets up with Olivier, an old friend who harbors a secret love for her, and who could draw her back to reality.","popularity":7.918,"poster_path":"/teDQRqy5STEhSvLERfGERBX25Br.jpg","production_companies":[{"id":591,"logo_path":"/q5I5RDwMEiqoNmfaJgd2LraEOJY.png","name":"France 3 Cinéma","origin_country":"FR"},{"id":1610,"logo_path":null,"name":"CED Productions","origin_country":""}],"production_countries":[{"iso_3166_1":"FR","name":"France"},{"iso_3166_1":"PL","name":"Poland"},{"iso_3166_1":"CH","name":"Switzerland"}],"release_date":"1993-09-08","revenue":0,"runtime":98,"spoken_languages":[{"english_name":"French","iso_639_1":"fr","name":"Français"},{"english_name":"Polish","iso_639_1":"pl","name":"Polski"}],"status":"Released","tagline":"","title":"Three Colors: Blue","video":false,"vote_average":7.7,"vote_count":1093}
MovieID=120 res={"adult":false,"backdrop_path":"/vRQnzOn4HjIMX4LBq9nHhFXbsSu.jpg","belongs_to_collection":{"id":119,"name":"The Lord of the Rings Collection","poster_path":"/nSNle6UJNNuEbglNvXt67m1a1Yn.jpg","backdrop_path":"/bccR2CGTWVVSZAG0yqmy3DIvhTX.jpg"},"budget":93000000,"genres":[{"id":12,"name":"Adventure"},{"id":14,"name":"Fantasy"},{"id":28,"name":"Action"}],"homepage":"http://www.lordoftherings.net/","id":120,"imdb_id":"tt0120737","original_language":"en","original_title":"The Lord of the Rings: The Fellowship of the Ring","overview":"Young hobbit Frodo Baggins, after inheriting a mysterious ring from his uncle Bilbo, must leave his home in order to keep it from falling into the hands of its evil creator. Along the way, a fellowship is formed to protect the ringbearer and make sure that the ring arrives at its final destination: Mt. Doom, the only place where it can be destroyed.","popularity":78.395,"poster_path":"/6oom5QYQ2yQTMJIbnvbkBL9cHo6.jpg","production_companies":[{"id":12,"logo_path":"/iaYpEp3LQmb8AfAtmTvpqd4149c.png","name":"New Line Cinema","origin_country":"US"},{"id":11,"logo_path":"/6FAuASQHybRkZUk08p9PzSs9ezM.png","name":"WingNut Films","origin_country":"NZ"},{"id":5237,"logo_path":null,"name":"The Saul Zaentz Company","origin_country":"US"},{"id":174,"logo_path":"/IuAlhI9eVC9Z8UQWOIDdWRKSEJ.png","name":"Warner Bros. Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"NZ","name":"New Zealand"},{"iso_3166_1":"US","name":"United States of America"}],"release_date":"2001-12-18","revenue":871368364,"runtime":179,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Released","tagline":"One ring to rule them all","title":"The Lord of the Rings: The Fellowship of the Ring","video":false,"vote_average":8.4,"vote_count":19453}
MovieID=220 res={"adult":false,"backdrop_path":"/u7i1XtbOubq0xwRy2Zbgmox6g9W.jpg","belongs_to_collection":null,"budget":1,"genres":[{"id":18,"name":"Drama"},{"id":10749,"name":"Romance"}],"homepage":"","id":220,"imdb_id":"tt0048028","original_language":"en","original_title":"East of Eden","overview":"In the Salinas Valley in and around World War I, Cal Trask feels he must compete against overwhelming odds with his brother for the love of their father. Cal is frustrated at every turn, from his reaction to the war, how to get ahead in business and in life, and how to relate to his estranged mother.","popularity":8.989,"poster_path":"/xv1MZVIop0SQqwLUymgE5eb2LFl.jpg","production_companies":[{"id":174,"logo_path":"/IuAlhI9eVC9Z8UQWOIDdWRKSEJ.png","name":"Warner Bros. Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"release_date":"1955-03-09","revenue":5,"runtime":115,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Released","tagline":"The searing classic of paradise lost!","title":"East of Eden","video":false,"vote_average":7.6,"vote_count":496}
MovieID=221 res={"adult":false,"backdrop_path":"/jPXsPciwlPTG756CHkZt2jYpnNM.jpg","belongs_to_collection":null,"budget":1500000,"genres":[{"id":18,"name":"Drama"}],"homepage":"","id":221,"imdb_id":"tt0048545","original_language":"en","original_title":"Rebel Without a Cause","overview":"After moving to a new town, troublemaking teen Jim Stark is supposed to have a clean slate, although being the new kid in town brings its own problems. While searching for some stability, Stark forms a bond with a disturbed classmate, Plato, and falls for local girl Judy. However, Judy is the girlfriend of neighborhood tough, Buzz. When Buzz violently confronts Jim and challenges him to a drag race, the new kid's real troubles begin.","popularity":7.809,"poster_path":"/qNmYLRadv106IhG6T2wSFH3Bc7W.jpg","production_companies":[{"id":174,"logo_path":"/IuAlhI9eVC9Z8UQWOIDdWRKSEJ.png","name":"Warner Bros. Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"release_date":"1955-10-29","revenue":199963,"runtime":111,"spoken_languages":[{"english_name":"English","iso_639_1":"en","name":"English"}],"status":"Released","tagline":"The bad boy from a good family.","title":"Rebel Without a Cause","video":false,"vote_average":7.6,"vote_count":1126}
MovieID=225 res={"adult":false,"backdrop_path":"/row4sMw5mVzKCWRbyrAQ39zvyLX.jpg","belongs_to_collection":{"id":457305,"name":"Solidarity Trilogy","poster_path":null,"backdrop_path":null},"budget":0,"genres":[{"id":18,"name":"Drama"},{"id":36,"name":"History"}],"homepage":"","id":225,"imdb_id":"tt0082222","original_language":"pl","original_title":"Człowiek z żelaza","overview":"In Warsaw in 1980, the Communist Party sends Winkel, a weak, alcoholic TV hack, to Gdansk to dig up dirt on the shipyard strikers, particularly on Maciek Tomczyk, an articulate worker whose father was killed in the December 1970 protests. Posing as sympathetic, Winkel interviews the people surrounding Tomczyk, including his detained wife, Agnieszka.","popularity":3.552,"poster_path":"/22wNUqKyz2m6wzAt31f26H8Y433.jpg","production_companies":[{"id":12838,"logo_path":null,"name":"Film Polski","origin_country":"PL"},{"id":6804,"logo_path":null,"name":"Zespól Filmowy \"X\"","origin_country":""}],"production_countries":[{"iso_3166_1":"PL","name":"Poland"}],"release_date":"1981-07-27","revenue":0,"runtime":147,"spoken_languages":[{"english_name":"Polish","iso_639_1":"pl","name":"Polski"},{"english_name":"Hungarian","iso_639_1":"hu","name":"Magyar"}],"status":"Released","tagline":"","title":"Man of Iron","video":false,"vote_average":6.9,"vote_count":37}
MovieID=234 exception=java.lang.RuntimeException: Timeout
MovieID=254 exception=java.lang.RuntimeException: Timeout
MovieID=256 exception=java.lang.RuntimeException: Timeout

You can see some requests are completed and some have timed out. We can combine result and send it as response.

Please comment if you need any clarification.

No comments:

Post a Comment