API called within forEach loop using unexpected appsmith.store value

Hello, Im using Bitbucket API and the JS Object. Im attempting to get data from a subquery using a stored value from the parent query. My second query seems to be returning the same data for every object in the forEach loop. When including the appsmith.store.repoName output I noticed its not using the correct value, but seems to be using the last repoName that was returned from the first query (getRepositories).

The below is getting all the repositories from bitbucket, then foreach of these, its attempting to pull down the envionrment list for this repository. (Im then trying to get the uuid value from this subquery if its a production environment)

My JSObject is below:

export default {
	test: async () => {	
		const tableData = [];
		 getRepositories.data.values.forEach((repo) => {
			storeValue('repoName', repo.name);	
			const uuid =  getRepoEnvironments.data.values.find(env => env.slug == 'production')?.uuid || 'default';
			
			const temp = {
				name: repo.name,
				searched: appsmith.store.repoName,
				uuid: uuid
			}
			tableData.push(temp);  
		});
		return tableData;
	} 
}

getRepositories API looks like: https://api.bitbucket.org/2.0/repositories/workspace/

getRepoEnvironments API looks like:
https://api.bitbucket.org/2.0/repositories/workspace/{{appsmith.store.repoName}}/environments/

The output looks like

{
"response":[
0:{
"name":"temp-repo-one"
"searched":"last-repo-three"
"uuid":"{3r34t34t}"
}
1:{
"name":"temp-repo-two"
"searched":"last-repo-three"
"uuid":"{3r34t34t}"
}
2:{
"name":"last-repo-three"
"searched":"last-repo-three"
"uuid":"{3r34t34t}"
}]
}

Is there a way i can get the appsmith.store.repo value to reflect the current repo.name in the loop so its pulled back the correct environment data?

Hi there!
Could you try:

const result = await getRepositories.run()
result.data.values.forEach((repo) => {...});

Bascially, what I’m suggesting is that you run the queries first with an await and store the response in a variable, then use the variables as you wish.

Also, changed the uuid section to:

const envs = await getRepoEnvironments.run() 
const uuid = envs.data.values.find(env => {...})

Try those and let me know if there’s any changes in the behaviour

Thanks Olawale, this suggestion did solve my issue but ive run into another, the loop now runs sequentially, it does work and pull back the correct data I need but is slow, when trying to use promise.all im having problems with the appsmith.store variables.

How does the appsmith.store handle variables set in async functions?

It seems to be overridding the variables.

Is there a way I can use the appsmith.store to store variables to be accessed in the API calls URL where they are called in parallel?

Many thanks

Can you try to add await wherever you’re using the storeValue() ?
Something like await storeValue('KEY', 'VALUE')

Still same issue :frowning:

Continues to update the storeValue keys with what appears to be the last item in the loop, ive changed my JS object to the below:

export default {
	getRepoData: async () => {	
	   const repoList = ["repo1", "repo2", "repo3"];

  	   const promises = [];
	   for (let i = 0; i < repoList.length; i++) {
		const repo = repoList[i];
		promises.push((async () => {			
			let deployedBy = "No Deployer";

			await storeValue('repoSlug', repo);	
			console.log("Loop item " + repo + " - StoreValue " + appsmith.store.repoSlug);
			const repoEnvironments = await getRepoEnvironments.run();
			const uuid = repoEnvironments.values.find(object => object.slug.toLowerCase() == environmentList.selectedOptionValue)?.uuid || 'default';		
				
			if(uuid != "default"){
				await storeValue('environmentUuid', uuid);
				console.log(repo + " - " + appsmith.store.repoSlug + " UUID: " + appsmith.store.environmentUuid + " " + uuid );
					
				const repoDeploymentData = await getRepoDeployments.run();
				if(repoDeploymentData.values.length > 0 && repoDeploymentData.values[0].state.name == "COMPLETED"){
					deployedBy = repoDeploymentData.values[0].state.deployer?.display_name || "No Deployer";

                                        // more data being pulled here
				}
			}

			let tempTable = {
				name:repo,
				deployedBy:deployedBy
			}

			return tempTable;					
		})());
	}
  	const results = await Promise.all(promises);
		
	return results;
	} 
}

The console output is below:

Loop item repo1 - StoreValue repo3       JS.GETREPODATA
Loop item repo2 - StoreValue repo3       JS.GETREPODATA
Loop item repo3 - StoreValue repo3       JS.GETREPODATA
repo1 - repo3 UUID: {7d8a4...} {7d8a4...       JS.GETREPODATA
repo2 - repo3 UUID: {7d8a4...} {7d8a4...       JS.GETREPODATA
repo3 - repo3 UUID: {7d8a4...} {7d8a4...       JS.GETREPODATA

If i was to run the main loop one at a time, this works just fine but is very slow as the number of repos i’m going over is high, Ideally my goal is to have all the items in the repoList main loop run in parallel.

Hi there! Although this isn’t working the way you want it to, It’s working as I expect it to.
Promise.all() is a promise concurrency method and what you’re experiencing is a data race issue. Somehow, they’re all holding the same reference to the variable when they’re about to be executed.

If you try this without promise.all(), you’ll realise that they work perfectly so, this isn’t really an issue with appsmith, it’s just a semantic issue.

One solution I can recommend is to pass repo as a parameter to the function like so:

for (let i = 0; i < repoList.length; i++) {
  const repo = repoList[i];
  promises.push((async (repoID) => {...})(repo));

}

and then you reference the repoID within those functions. Can you try that and see if it works?

Hi Olawale, thanks so much for the help, unfortunately I’m still not able to get it working the way id expect.

Are you able to provide more of an example?

Thanks again.

Hey Kelly!
It might be a bit tedious to provide any example that will be inline with your use case right now.
Could you invite support@appsmith.com as Developer to your workspace and share the link to your app with us so we can debug it?