dherault / serverless-offline

Emulate AWS λ and API Gateway locally when developing your Serverless project
MIT License
5.19k stars 796 forks source link

serverless offline doesn't work with Java package that has many class files #1686

Open MatthiasBoehm87 opened 1 year ago

MatthiasBoehm87 commented 1 year ago

Bug Report

Current Behavior

If you run serverless offline with the serverless.yml file below, and the Java package contains many class files, serverless offline fails with the following message when invoking the GET endpoint (the name of the class file is random):

× EMFILE: too many open files, open 'C:\Users\...\Documents\BugServerlessOffline\.serverless-offline\services\bugserverlessoffline\hello\efc4c712-3754-45b6-a153-6f14049501d3\code\software\amazon\awssdk\services\route53\model\UpdateHostedZoneCommentRequest$1.class'

image

The serverless.yml file is as follows:

service: bugserverlessoffline

frameworkVersion: '3'

provider:
  name: aws
  runtime: java8

plugins:
  - serverless-offline

package:
  artifact: target/hello-dev.jar

functions:
  hello:
    handler: com.serverless.Handler
    events:
      - http:
          path: /hello
          method: GET

serverless offline fails while unpacking the hello-dev.jar-file to the .serverless-offline folder. Either while extracting there are too many files opened at the same moment or the files are not closed.

I fixed this problem by modifying serverless-offline\src\lambda\LambdaFunction.js as follows:

  1. Added import: import { writeFileSync } from 'fs'
  2. In the function extractArtifact I replaced the line return writeFile(join(this.#codeDir, filename), fileData, { by return writeFileSync(join(this.#codeDir, filename), fileData, {

Here is the patch for these changes: LambdaFunction.js.patch

Sample Code

I've created a simple sample application with serverless create --template aws-java-maven, and added a lot of dependencies to the pom.xml file:

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>bom</artifactId>
        <version>2.20.49</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>org.junit</groupId>
        <artifactId>junit-bom</artifactId>
        <version>5.9.2</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-log4j2</artifactId>
      <version>1.5.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.20.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <version>2.20.0</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.14.2</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.14.2</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.14.2</version>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>s3</artifactId>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>dynamodb</artifactId>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>dynamodb-enhanced</artifactId>
    </dependency>
    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>route53</artifactId>
    </dependency>
    <dependency>
      <groupId>com.amazonaws</groupId>
      <artifactId>aws-lambda-java-events</artifactId>
      <version>3.11.0</version>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
      <version>2.10.1</version>
    </dependency>
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-api</artifactId>
      <version>0.11.5</version>
    </dependency>
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-impl</artifactId>
      <version>0.11.5</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
      <version>0.11.5</version>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt-root</artifactId>
      <version>0.11.5</version>
      <type>pom</type>
    </dependency>

I then also modified the serverless.yml slightly (added GET /hello endpoint).

Here is the complete sample application: BugServerlessOffline.zip

Expected behavior/code

Serverless offline shouldn't fail.

Environment

Possible Solution

See above.

Additional context/Screenshots

None.