From 85c359b70a1b2337d196c5cdc45b194c42a01987 Mon Sep 17 00:00:00 2001 From: Sergio Barrio Date: Fri, 30 Jan 2026 15:54:04 +0100 Subject: [PATCH] Introduce request queue and gertByIds fetch on rumAuto scenario --- .../RUM/Auto/screens/characterDetail.tsx | 7 +- .../RUM/Auto/screens/episodeDetail.tsx | 8 +- .../RUM/Auto/screens/locationDetail.tsx | 8 +- .../scenario/RUM/Auto/service/rickMorty.ts | 118 ++++++++++++++++-- 4 files changed, 115 insertions(+), 26 deletions(-) diff --git a/benchmarks/src/scenario/RUM/Auto/screens/characterDetail.tsx b/benchmarks/src/scenario/RUM/Auto/screens/characterDetail.tsx index 20329c589..a2445b58f 100644 --- a/benchmarks/src/scenario/RUM/Auto/screens/characterDetail.tsx +++ b/benchmarks/src/scenario/RUM/Auto/screens/characterDetail.tsx @@ -33,9 +33,8 @@ function CharacterDetailScreen(): React.JSX.Element { const onShowEpisodes = async () => { try { - const episodeNames = await Promise.all(episodeURLs.map((url) => - RickMortyService.fetchRequest(url).then(json => json.name) - )); + const episodeData = await RickMortyService.fetchEpisodesByIds(episodeURLs); + const episodeNames = episodeData.map(episode => episode.name); setEpisodes(episodeNames); } catch (_error) { Alert.alert("Something went wrong. Please try again later."); @@ -86,4 +85,4 @@ function CharacterDetailScreen(): React.JSX.Element { ); }; -export default CharacterDetailScreen; \ No newline at end of file +export default CharacterDetailScreen; diff --git a/benchmarks/src/scenario/RUM/Auto/screens/episodeDetail.tsx b/benchmarks/src/scenario/RUM/Auto/screens/episodeDetail.tsx index a6a280af8..fb8d92dcc 100644 --- a/benchmarks/src/scenario/RUM/Auto/screens/episodeDetail.tsx +++ b/benchmarks/src/scenario/RUM/Auto/screens/episodeDetail.tsx @@ -38,10 +38,8 @@ function EpisodeDetailScreen(): React.JSX.Element { const getCharacters = async () => { try { setIsLoading(true); - const charaterList = await Promise.all(characterURLS.map((url) => - RickMortyService.fetchRequest(url).then(json => json as Character) - )); - setCharacters(charaterList); + const characterList = await RickMortyService.fetchCharactersByIds(characterURLS); + setCharacters(characterList as Character[]); } catch (_error) { Alert.alert("Something went wrong. Please try again later."); } finally { @@ -103,4 +101,4 @@ function EpisodeDetailScreen(): React.JSX.Element { ); }; -export default EpisodeDetailScreen; \ No newline at end of file +export default EpisodeDetailScreen; diff --git a/benchmarks/src/scenario/RUM/Auto/screens/locationDetail.tsx b/benchmarks/src/scenario/RUM/Auto/screens/locationDetail.tsx index 263a31c17..cde7a95e6 100644 --- a/benchmarks/src/scenario/RUM/Auto/screens/locationDetail.tsx +++ b/benchmarks/src/scenario/RUM/Auto/screens/locationDetail.tsx @@ -38,10 +38,8 @@ function LocationDetailScreen(): React.JSX.Element { const getCharacters = async () => { try { setIsLoading(true); - const charaterList = await Promise.all(characterURLS.map((url) => - RickMortyService.fetchRequest(url).then(json => json as Character) - )); - setCharacters(charaterList); + const characterList = await RickMortyService.fetchCharactersByIds(characterURLS); + setCharacters(characterList as Character[]); } catch (_error) { Alert.alert("Something went wrong. Please try again later."); } finally { @@ -103,4 +101,4 @@ function LocationDetailScreen(): React.JSX.Element { ); }; -export default LocationDetailScreen; \ No newline at end of file +export default LocationDetailScreen; diff --git a/benchmarks/src/scenario/RUM/Auto/service/rickMorty.ts b/benchmarks/src/scenario/RUM/Auto/service/rickMorty.ts index 2c776dfef..8a15a120b 100644 --- a/benchmarks/src/scenario/RUM/Auto/service/rickMorty.ts +++ b/benchmarks/src/scenario/RUM/Auto/service/rickMorty.ts @@ -10,27 +10,121 @@ const CHARACTERS_ENDPOINT = "character"; const LOCATIONS_ENDPOINT = "location"; const EPISODES_ENDPOINT = "episode"; +const MAX_CONCURRENT_REQUESTS = 1; +const REQUEST_DELAY_MS = 600; +interface QueuedRequest { + url: string; + resolve: (value: any) => void; + reject: (error: any) => void; +} + class RickMortyService { - fetchRequest(url: string, page?: number) { - const fullURL = url + (page ? ("?page=" + page.toString()) : ''); - return fetch(fullURL).then((data) => { - return data.json(); - }).catch((_error) => { - return Promise.reject(); - }) - }; + private requestQueue: QueuedRequest[] = []; + private activeRequests = 0; + private isProcessing = false; + + private delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + private async processQueue(): Promise { + if (this.isProcessing) { + return; + } + + this.isProcessing = true; + + while (this.requestQueue.length > 0 && this.activeRequests < MAX_CONCURRENT_REQUESTS) { + const request = this.requestQueue.shift(); + if (!request) break; + + this.activeRequests++; + + try { + await this.delay(REQUEST_DELAY_MS); + + const response = await fetch(request.url); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + request.resolve(data); + } catch (error) { + request.reject(error); + } finally { + this.activeRequests--; + } + } + + this.isProcessing = false; + + if (this.requestQueue.length > 0) { + this.processQueue(); + } + } + + fetchRequest(url: string, page?: number): Promise { + const fullURL = url + (page ? `?page=${page}` : ''); + + return new Promise((resolve, reject) => { + this.requestQueue.push({ + url: fullURL, + resolve, + reject + }); + + this.processQueue(); + }); + } + + private extractIdFromUrl(url: string): string | null { + const match = url.match(/\/(\d+)$/); + return match ? match[1] : null; + } + + private async fetchByIds(endpoint: string, urls: string[], resourceType: string): Promise { + const ids = urls.map(url => this.extractIdFromUrl(url)).filter(Boolean); + if (ids.length === 0) return []; + + const batchUrl = `${BASE_URL}/${endpoint}/${ids.join(',')}`; + + try { + const response = await fetch(batchUrl); + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + const data = await response.json(); + return Array.isArray(data) ? data : [data]; + } catch (error) { + throw error; + } + } fetchCharacters(page?: number) { return this.fetchRequest(BASE_URL + "/" + CHARACTERS_ENDPOINT, page); - }; + } fetchLocations(page?: number) { return this.fetchRequest(BASE_URL + "/" + LOCATIONS_ENDPOINT, page); - }; + } fetchEpisodes(page?: number) { return this.fetchRequest(BASE_URL + "/" + EPISODES_ENDPOINT, page); - }; + } + + fetchCharactersByIds(urls: string[]): Promise { + return this.fetchByIds(CHARACTERS_ENDPOINT, urls, 'characters'); + } + + fetchEpisodesByIds(urls: string[]): Promise { + return this.fetchByIds(EPISODES_ENDPOINT, urls, 'episodes'); + } + + fetchLocationsByIds(urls: string[]): Promise { + return this.fetchByIds(LOCATIONS_ENDPOINT, urls, 'locations'); + } }; -export default new RickMortyService(); \ No newline at end of file +export default new RickMortyService();