3

When I run serverless offline with both Node and Python runtimes, I get the following error upon hitting a Python endpoint:

Traceback (most recent call last):
  File "/foo/node_modules/serverless-offline/dist/lambda/handler-runner/python-runner/invoke.py", line 76, in <module>
    module = import_module(args.handler_path.replace(os.sep, '.'))
  File "/foo/venv/lib/python3.6/importlib/__init__.py", line 121, in import_module
    raise TypeError(msg.format(name))
TypeError: the 'package' argument is required to perform a relative import for '.webpack.service.src.utilsPy'

I can successfully hit the Node runtime.

If I instead run serverless offline --location ., I am able to successfully go to the Python endpoint, but the Node endpoint gives me this error

Failure: Cannot find module '/foo/src/utils'

Require stack: <removed stack trace>

Is there a way to run both offline? I can deploy both runtimes and it works, it's just serverless offline that doesn't work. Source files below.

P.S.: I created an issue on the serverless-offline repo.

Sample Code

  • file: serverless.yml
service  :
  name: ${self:custom.serviceName}
custom   :
  packageJson       : ${file(./package.json)}
  serviceName       : ${self:custom.packageJson.name}
  webpack           :
    webpackConfig : ./webpack.config.js
    includeModules: true
  serverless-offline:
    httpPort: 4000
  pythonRequirements:
    dockerizePip: true
plugins:
  - serverless-webpack
  - serverless-offline
  - serverless-pseudo-parameters
  - serverless-python-requirements
provider :
  name              : aws
  runtime           : nodejs12.x
  <removed a bunch of parameters not relevant to this>
functions:
 - ${file(some-other-file-not-relevant.yml)}
  - health:
      name       : ${self:service}-${self:provider.stage}-health
      description: Health check endpoint
      handler    : src/utils.handler
      memorySize : 128
      timeout    : 10
      events     :
        - http:
            path  : /health
            method: GET
            cors  : true
  - health-py:
      name       : ${self:service}-${self:provider.stage}-health-py
      runtime    : python3.6
      description: Health check endpoint for python
      handler    : src/utilsPy.handler
      memorySize : 128
      timeout    : 10
      events     :
        - http:
            path  : /health-py
            method: GET
            cors  : true
  • file: webpack.config.js
const path = require('path');
const slsw = require('serverless-webpack');
const nodeExternals = require('webpack-node-externals');
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

// CUSTOM CODE: Remove Python files as entry points
const entries = {};
Object.keys(slsw.lib.entries).forEach(
    key => {
      if (!slsw.lib.entries[key].match(/\.py$/)) {
        entries[key] = [slsw.lib.entries[key]]
      }
    }
);

module.exports = {
  context: __dirname,
  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',
  entry: entries, // CUSTOM CODE: Uses custom entry above
  devtool: slsw.lib.webpack.isLocal ? 'cheap-module-eval-source-map' : 'source-map',
  resolve: {
    extensions: ['.mjs', '.json', '.ts'],
    symlinks: false,
    cacheWithContext: false,
  },
  output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, '.webpack'),
    filename: '[name].js',
  },
  target: 'node',
  externals: [nodeExternals()],
  module: {
    rules: [
      // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
      {
        test: /\.(tsx?)$/,
        loader: 'ts-loader',
        exclude: [
          [
            path.resolve(__dirname, 'node_modules'),
            path.resolve(__dirname, '.serverless'),
            path.resolve(__dirname, '.webpack'),
          ],
        ],
        options: {
          transpileOnly: true,
          experimentalWatchApi: true,
        },
      },
    ],
  },
  plugins: [
    // new ForkTsCheckerWebpackPlugin({
    //   eslint: true,
    //   eslintOptions: {
    //     cache: true
    //   }
    // })
  ],
};
  • file: utils.ts
import { APIGatewayProxyHandler } from 'aws-lambda';
import 'source-map-support/register';
/**
 * A simle health check endpoint...
 * @param event
 * @param _context
 */
export const handler: APIGatewayProxyHandler = async (event, _context) => {
    return {
        statusCode: 200,
        body: JSON.stringify({
            message: 'Healthy!',
            input: event,
        }, null, 2),
    };
};
  • file: utilsPy.py
"""
    A simple health checkpoint for python
"""
import json
def handler(event, context):
    return {
            'statusCode': 200,
            'body':
            json.dumps({
              'message':'Healthy Python!',
              'input': event
              })
            }
lebolo
  • 2,120
  • 4
  • 29
  • 44

0 Answers0