amazon-web-servicesserverlessamazon-snsaws-serverlessserverless-offline

Serverless offline failing to start with serverless-offline-sns


I am getting this error trying to run serverless offline:

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/mypc/Downloads/textai/src/functions/processExpenseAnalysisJob.js' imported from /home/mypc/Downloads/textai/node_modules/serverless-offline-sns/dist/index.js

I was trying to add serverless-offline-sns to work in local, but I can't seem to start the app if I put it in plugins, if I remove it, it works. I already deleted node_modules and a npm install. Do I need to use something additional like working with serverless-offline-sqs which I needed elastiqmq? I am using SNS with from:

    const command = new StartExpenseAnalysisCommand({
      DocumentLocation: {
        S3Object: {
          Bucket: fileObj.s3.bucket.name,
          Name: fileObj.s3.object.key,
        },
      },
      NotificationChannel: {
        SNSTopicArn: process.env.SNS_TOPIC_ARN,
        RoleArn: process.env.ROLE_ARN,
      },
    });

Which will trigger processExpenseAnalysisJob handler, before I was testing deploying and it works there perfectly.

My serverless.yml

service: ${env:APP_SERVICE_NAME}
useDotenv: true
configValidationMode: warn

plugins:
  - serverless-offline-sqs
  - serverless-offline-sns
  - serverless-offline
  - serverless-plugin-typescript
  - serverless-plugin-optimize

provider:
  name: aws
  runtime: nodejs18.x
  memorySize: 128
  region: ${env:AWS_REGION}
  stage: ${opt:stage,'dev'}
  environment:
    # APP
    APP_STAGE: ${env:APP_STAGE}
    APP_SERVICE_NAME: ${env:APP_SERVICE_NAME}
    AWS_ACCOUNT_ID: ${env:AWS_ACCOUNT_ID}
    DEVELOPMENT_PATH: ${env:DEVELOPMENT_PATH}
    EXCHANGE_RATE_API: ${env:EXCHANGE_RATE_API}
    SNS_TOPIC_ARN: !GetAtt TextractTriggerTopic.TopicArn
    ROLE_ARN: ${env:ROLE_ARN}

  iam:
    role:
      statements:
        - Effect: Allow
          Action:
            - sqs:SendMessage
            - sqs:ReceiveMessage
            - sqs:DeleteMessage
          Resource: !GetAtt MySQSQueue.Arn
        - Effect: Allow
          Action:
            - textract:StartExpenseAnalysis
            - textract:GetExpenseAnalysis
          Resource: "*"
        - Effect: Allow
          Action:
            - s3:GetObject
            - s3:PutObject
          Resource: "*"
        - Effect: Allow
          Action:
            - sns:Publish
          Resource: !GetAtt TextractTriggerTopic.TopicArn
        - Effect: Allow
          Action:
            - lambda:InvokeFunction
          Resource: "*"

functions:
  startExpenseAnalysisJob:
    handler: src/functions/startExpenseAnalysisJob.handler
    timeout: 180
    maximumRetryAttempts: 1
    events:
      - sqs:
          arn: !GetAtt MySQSQueue.Arn
  processExpenseAnalysisJob:
    handler: src/functions/processExpenseAnalysisJob.handler
    events:
      - sns:
          arn: !GetAtt TextractTriggerTopic.TopicArn
          topicName: TextractTriggerTopic-${self:provider.stage}

resources:
  Resources:
    MySQSQueue:
      Type: AWS::SQS::Queue
      Properties:
        QueueName: TextractTriggerQueue-${self:provider.stage}
        VisibilityTimeout: 360

    TextractTriggerTopic:
      Type: AWS::SNS::Topic
      Properties:
        TopicName: TextractTriggerTopic

custom:
  serverless-offline-sqs:
    autoCreate: true
    apiVersion: "2012-11-05"
    endpoint: http://0.0.0.0:9324
    region: ${self:provider.region}
    accessKeyId: root
    secretAccessKey: root
    skipCacheInvalidation: false

  serverless-offline-sns:
    port: 4002
    debug: false
    host: 0.0.0.0
    endpoint: http://localhost:4001

And this is my package.json

  "devDependencies": {
    "@types/aws-lambda": "^8.10.134",
    "dotenv": "^16.4.5",
    "prettier": "^3.2.5",
    "serverless": "^3.38.0",
    "serverless-offline": "^13.3.3",
    "serverless-offline-sns": "^0.77.2",
    "serverless-offline-sqs": "^8.0.0",
    "serverless-plugin-optimize": "^4.2.1-rc.1",
    "serverless-plugin-typescript": "^2.1.5",
    "ts-node": "^10.9.2",
    "typescript": "^5.3.3"
  },
  "dependencies": {
    "@aws-sdk/client-s3": "^3.525.0",
    "@aws-sdk/client-sqs": "^3.525.0",
    "@aws-sdk/client-textract": "^3.525.0",
    "amazon-textract-response-parser": "^0.4.0",
    "axios": "^1.6.7"
  }

Update: Is there anyone that knows? I can't seem to find the problem. But the part that gives me that error is this section of my serverless.yml:

functions:
  ......
  processExpenseAnalysisJob:
    handler: src/functions/processExpenseAnalysisJob.handler
    events:
      - sns:
          arn: arn:aws:sns:${self:provider.region}:${aws:accountId}:TextractTriggerTopic
  .....

When I add the sns event to my lambda function, if I remove the event it works, but I can't seem to find what's wrong following this: https://www.serverless.com/plugins/serverless-offline-sns#configure. Before I had !GetAtt TextractTriggerTopic.TopicArn but changed it as serverless-offline-sns doesn't recognize !GetAtt when running serverless offline.


Solution

  • I found the solution for anyone wondering...

    The error was the order for my serverless.yml plugins, which should be the following:

    plugins:
      - serverless-plugin-typescript  # Must be before transpilation plugins
      - serverless-plugin-optimize    # Can be before or after transpilation
      - serverless-offline-sns       # Can be in any order
      - serverless-offline-sqs       # Can be in any order
      - serverless-offline           # Must be last
    

    Following this order ensures that the plugins are executed in the correct sequence to achieve the desired outcome: transpiling TypeScript, potentially optimizing the code, and then setting up the offline environment.