skip to Main Content

I am facing an issue with the execution order of recursive RxJS Observables in an Angular application. I have a service, RefreshReportService, which is responsible for refreshing reports. The refreshreport method is designed to refresh a report and its nested reports recursively.

The problem is that the recursive calls seem to be running in parallel instead of waiting for the completion of the previous one. Here is a simplified version of the code:

refreshreport(report_name: string): Observable<any> {
    let operations_list: any = [];
    let primary_key: string = "";

    return new Observable((observer) => {
        this.ifreportisfromotherreports(report_name, (nestedreports: any[]) => {
            if (nestedreports) {
                const recursiveCalls = nestedreports.map((nested_report_name) => {
                    return this.refreshreport(nested_report_name);
                });

                from(recursiveCalls).pipe(
                    concatMap((recursiveCall) => recursiveCall)
                ).subscribe({
                    next: (response: any) => { console.log(response); },
                    error: (err) => { console.log(err); },
                    complete: () => {
                        // Continue with the rest of the logic after recursive calls
                        observer.complete();
                    }
                });
            } 
            const token = localStorage.getItem('auth-token');
            const headers = new HttpHeaders({
                'Authorization': `token ${token}`
            });

            const formData = new FormData();
            formData.append('report_name', report_name);

            this.http.post('http://127.0.0.1:8000/getreportoperationslist', formData, { headers, withCredentials: true }).subscribe({
                next: (response: any) => {
                    operations_list = response.operations_list;
                    primary_key = response.primary_key;
                },
                error: (err) => {
                    console.log(err);
                },
                complete: () => {
                    const updateapicalls: Observable<any>[] = [];

                    operations_list.forEach((operation: any) => {
                        updateapicalls.push(this.createRequestObservable(operation));
                    });

                    from(updateapicalls).pipe(
                        concatMap((observable) => observable)
                    ).subscribe({
                        next: (response: any) => { console.log(response); },
                        error: (err) => { console.log(err); },
                        complete: () => {
                            this.DeleteReport(report_name, primary_key);
                            observer.complete(); // Notify the outer observer that this recursion is complete
                        }
                    });
                }
            });           
        });
    });
}

I want the recursive calls to run sequentially, waiting for the completion of the previous one before moving on to the next. Any insights into how I can achieve this would be greatly appreciated!

enter image description here

This is snap of the networks tab in here, the first one is of the most-outer function, while the second one is of the recursive function (which is correct), but the things screw up from the 3rd one, which of the outer one.. and further calls are all incorrect order of calls

I tried to run the code, but the order is not correct, i expected correct order of calling, first the function calls of the inside one’s and then the outer one’s.

2

Answers


  1. Chosen as BEST ANSWER

    The issue was : not waiting for the updateapicalls[] to get completed ( by applying await ) which made the control to shift back to the parent function, This is the updated code for the same ` async refreshreports(report_name: string): Promise { // Get nested reports (if any) const nestedReports: string[] | undefined = await new Promise((resolve, reject) => { this.ifreportisfromotherreports(report_name, (nestedreports: any[]) => { if (nestedreports) { resolve(nestedreports); } else { resolve(undefined); } }); });

        // Process nested reports
        if (nestedReports) {
          for (const nested_report_name of nestedReports) {
            await this.refreshreports(nested_report_name);
          }
        }
      
        // Get operations list and primary key
        let operationsList: any[] = [];
        let primaryKey: string = "";
      
        const token = localStorage.getItem('auth-token');
        const headers = new HttpHeaders({
          'Authorization': `token ${token}`,
        });
      
        const formData = new FormData();
        formData.append('report_name', report_name);
      
        await this.http
          .post('http://127.0.0.1:8000/getreportoperationslist', formData, { headers, withCredentials: true })
          .toPromise()
          .then((response: any) => {
            operationsList = response.operations_list;
            primaryKey = response.primary_key;
          })
          .catch((err) => {
            console.error(err);
          });
      
        // Create and execute update API calls
        const updateApiCalls: Observable<any>[] = [];
        operationsList.forEach((operation) => {
          updateApiCalls.push(this.createRequestObservable(operation));
        });
      
        await from(updateApiCalls)
          .pipe(concatMap((observable) => observable))
          .toPromise();
      
        // Delete report after all operations complete
        await this.DeleteReport(report_name, primaryKey);
      }
    

    `


  2. Complete will run after each api call in this pattern instead could you try this?

    toArray -> ensure next or complete will run after all the sequential executions!

    refreshreport(report_name: string): Observable<any> {
        let operations_list: any = [];
        let primary_key: string = "";
    
        return new Observable((observer) => {
            this.ifreportisfromotherreports(report_name, (nestedreports: any[]) => {
                if (nestedreports) {
                    const recursiveCalls = nestedreports.map((nested_report_name) => {
                        return this.refreshreport(nested_report_name);
                    });
    
                    from(recursiveCalls).pipe(
                        concatMap((recursiveCall) => recursiveCall),
                        toArray(), // -- changed here!
                    ).subscribe({
                        next: (response: any) => { console.log(response); },
                        error: (err) => { console.log(err); },
                        complete: () => {
                            // Continue with the rest of the logic after recursive calls
                            observer.complete();
                        }
                    });
                } 
                const token = localStorage.getItem('auth-token');
                const headers = new HttpHeaders({
                    'Authorization': `token ${token}`
                });
    
                const formData = new FormData();
                formData.append('report_name', report_name);
    
                this.http.post('http://127.0.0.1:8000/getreportoperationslist', formData, { headers, withCredentials: true }).subscribe({
                    next: (response: any) => {
                        operations_list = response.operations_list;
                        primary_key = response.primary_key;
                    },
                    error: (err) => {
                        console.log(err);
                    },
                    complete: () => {
                        const updateapicalls: Observable<any>[] = [];
    
                        operations_list.forEach((operation: any) => {
                            updateapicalls.push(this.createRequestObservable(operation));
                        });
    
                        from(updateapicalls).pipe(
                            concatMap((observable) => observable),
                            toArray(), // -- changed here!
                        ).subscribe({
                            next: (response: any) => { console.log(response); },
                            error: (err) => { console.log(err); },
                            complete: () => {
                                this.DeleteReport(report_name, primary_key);
                                observer.complete(); // Notify the outer observer that this recursion is complete
                            }
                        });
                    }
                });           
            });
        });
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search