Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot run both Node and Python offline runtimes simultaneously #993

Closed
lebolo opened this issue May 27, 2020 · 5 comments
Closed

Cannot run both Node and Python offline runtimes simultaneously #993

lebolo opened this issue May 27, 2020 · 5 comments

Comments

@lebolo
Copy link

lebolo commented May 27, 2020

Bug Report

Current Behavior
Running serverless offline with both Node and Python runtimes gives the following error when 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'

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
              })
            }

Expected behavior/code
Expecting to run both TypeScript and Python lambdas offline simultaneously.

Environment

  • serverless version: 1.71.3
  • serverless-offline version: 6.2.0
  • node.js version: 12.6.2
  • OS: macOS 10.14.6

optional, if you are using any of the following frameworks to invoke handlers

  • python version: 3.6

Additional context/Screenshots

When I run serverless offline, I am able to successfully go to the health endpoint (javascript), but going to the health-py endpoint gives me the error pasted above.

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

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

Require stack:
- /foo/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js
- /foo/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/index.js
- /foo/node_modules/serverless-offline/dist/lambda/handler-runner/HandlerRunner.js
- /foo/node_modules/serverless-offline/dist/lambda/handler-runner/index.js
- /foo/node_modules/serverless-offline/dist/lambda/LambdaFunction.js
- /foo/node_modules/serverless-offline/dist/lambda/LambdaFunctionPool.js
- /foo/node_modules/serverless-offline/dist/lambda/Lambda.js
- /foo/node_modules/serverless-offline/dist/lambda/index.js
- /foo/node_modules/serverless-offline/dist/ServerlessOffline.js
- /foo/node_modules/serverless-offline/dist/index.js
- /foo/node_modules/serverless-offline/dist/main.js
- /bar/.nave/installed/bender-sls/lib/node_modules/serverless/lib/classes/PluginManager.js
- /bar/.nave/installed/bender-sls/lib/node_modules/serverless/lib/Serverless.js
- /bar/.nave/installed/bender-sls/lib/node_modules/serverless/lib/utils/autocomplete.js
- /bar/.nave/installed/bender-sls/lib/node_modules/serverless/bin/serverless.js
Error: Cannot find module '/foo/src/utils'
Require stack:
- /foo/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js
- /foo/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/index.js
- /foo/node_modules/serverless-offline/dist/lambda/handler-runner/HandlerRunner.js
- /foo/node_modules/serverless-offline/dist/lambda/handler-runner/index.js
- /foo/node_modules/serverless-offline/dist/lambda/LambdaFunction.js
- /foo/node_modules/serverless-offline/dist/lambda/LambdaFunctionPool.js
- /foo/node_modules/serverless-offline/dist/lambda/Lambda.js
- /foo/node_modules/serverless-offline/dist/lambda/index.js
- /foo/node_modules/serverless-offline/dist/ServerlessOffline.js
- /foo/node_modules/serverless-offline/dist/index.js
- /foo/node_modules/serverless-offline/dist/main.js
- /bar/.nave/installed/bender-sls/lib/node_modules/serverless/lib/classes/PluginManager.js
- /bar/.nave/installed/bender-sls/lib/node_modules/serverless/lib/Serverless.js
- /bar/.nave/installed/bender-sls/lib/node_modules/serverless/lib/utils/autocomplete.js
- /bar/.nave/installed/bender-sls/lib/node_modules/serverless/bin/serverless.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:980:15)
    at Function.resolve (internal/modules/cjs/helpers.js:83:19)
    at InProcessRunner.run (/foo/node_modules/serverless-offline/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js:59:18)
    at HandlerRunner.run (/foo/node_modules/serverless-offline/dist/lambda/handler-runner/HandlerRunner.js:148:64)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at LambdaFunction.runHandler (/foo/node_modules/serverless-offline/dist/lambda/LambdaFunction.js:313:20)
    at hapiHandler (/foo/node_modules/serverless-offline/dist/events/http/HttpServer.js:463:18)
    at module.exports.internals.Manager.execute (/foo/node_modules/@hapi/hapi/lib/toolkit.js:45:28)
    at Object.internals.handler (/foo/node_modules/@hapi/hapi/lib/handler.js:46:20)
    at exports.execute (/foo/node_modules/@hapi/hapi/lib/handler.js:31:20)
    at Request._lifecycle (/foo/node_modules/@hapi/hapi/lib/request.js:312:32)
    at Request._execute (/foo/node_modules/@hapi/hapi/lib/request.js:221:9)
@barnc
Copy link

barnc commented Jul 7, 2020

Running into this same exact issue. Did you ever find a solution to this?

@lebolo
Copy link
Author

lebolo commented Jul 7, 2020

We did not. We ended up only using Python lambdas for this project =\

@garymcleanhall
Copy link

The problem is that the webpack output directory is prefixed with a period . - this makes python think that the import is package-relative, yet no package has been specified.

To fix, have webpack output everything to a directory without the . prefix:

output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, 'dist'),
    filename: '[name].js',
  },

@hongquan
Copy link

hongquan commented Jan 28, 2021

Our project doesn't have NodeJS, but we also ran into this error, at the same line:

module = import_module(args.handler_path.replace(os.sep, '.'))

We managed to fork serverless-offline and added a fix. But we are not sure if this solves other people's problem as well. In our case, the args.handler_path has a crazy path like ../../../../../../tmp/serverless-offline/services/ekyc-api/pykye/ckkg9e51y0002e8l113qz4f13/code/pykye.serverless, and when looking into that path, we don't see our code (pykye.serverless) copied to there. So our fix is just to let python-runner import the code right at project source folder, instead of in /tmp/ path.

@raytorres280
Copy link

raytorres280 commented May 18, 2021

I get the error even though on deploy my code works.

I can deploy my zip file using sls deploy and can hit the endpoint without error. Locally, using sls offline or sls offline --location . I get the same package argument error.

edit: It would be great if we could provide an artifact to sls offline the same way we do to serverless

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants