0

Here is a task - it's necessary to generate a file based on some data from the UI side (JavaScript). The schema is pretty simple:

  1. The UI makes an async POST HTTP request to the server and provides some JSON data:

        $.ajax({
            url: '/reports',
            type: "POST",
            data: JSON.stringify({...}),
            success: function (uuid) {                    
                window.location = "/reports/" + uuid;
            }                
        });
    
  2. The server receives the request, generates a file, puts it on the filesystem and returns the unique ID:

    @RequestMapping(value = "/reports", method = RequestMethod.POST)
    public String generateReport(ReqData data) throws IOException {
      final String fileUuid = UUID.randomUUID();
      ...
      //generate a report and return filename
      ...
      return fileUuid;
    }
    
  3. The UI sides gets the unique id of the file generated and requests it:

    success: function (uuid) {                    
      window.location = "/reports/" + uuid;
    }  
    
  4. The server outputs the file requested:

      @RequestMapping(value = "/reports/{uuid}", method = RequestMethod.GET)
      public ResponseEntity<InputStreamResource> downloadReport(@PathVariable("uuid") String fileUuid) throws IOException {
    
        final String resultFileName = fileUuid + ".txt";
        final Path resultFile = Paths.get(resultFileName);
    
        return ResponseEntity
                .ok()
                .header("Content-Disposition", "attachment; filename=\"" + resultFileName + "\"")
                .contentLength(Files.size(resultFile))
                .contentType(MediaType.parseMediaType("text/plain"))
                .body(new InputStreamResource(Files.newInputStream(resultFile)));
    } 
    

The problem starts when we consider this schema with multiple servers. If we have two instances Server_A and Server_B and a load balancer in the front of them then we need to make sure that the both requests mentioned above go to the same server. Thus sticky sessions are required. Providing an absolute path with the server specified like http://server_a/reports/123 is not a good option as we want to make all the servers unreachable from the outer world.

So what options are available to implement downloading files generated as well as avoid sticky sessions?

Stephen L.
  • 509
  • 2
  • 14

1 Answers1

0

There are couple of ways to implement a solution around this.. Although the session stickyness starts and is configured at the load-balancer.

Approach 1: -- make a NFS space available and have it mounted on all the application servers and generate the report in that location. Once mounted the same file can be served from any server.

Approach 2: Implement a local file repository on one of the servers and on generating the report push the file to the repository via ftp protocol, this approach may have a little performance impact at their will be an overhead of storing and retrieving the file via FTP.

Approach 3: Store the reports in the db itself and retrieve it via db from any server.

Approach 4: Why not send the report to the client at the time of generation itself, why not implement the delivery of the file along with the first call itself. in anyway in your javascript it appears that you are setting window.location on receiving the response after generating the file.

Jas
  • 336
  • 2
  • 7
  • Approach 4: it's impossible to trigger save dialog in the browser using ajax - http://stackoverflow.com/questions/12098178/prompt-user-to-save-file-through-ajax-call this is why there are two ajax calls – Stephen L. Dec 09 '15 at 03:00