serverless-azure-functions icon indicating copy to clipboard operation
serverless-azure-functions copied to clipboard

Incorrect Service Bus Out binding

Open stout01 opened this issue 6 years ago • 3 comments

This is a Bug Report

Description

  • What went wrong?
    • A default queueName is added to the function.json along with the specified topicName
  • What did you expect should have happened?
    • The queueName should not be included in the function.json
  • What was the config you used?
save-condition:
  handler: src/handlers/save-condition.handler
  name: save-condition
  events:
    - http: true
      x-azure-settings:
        methods:
          - POST
        authLevel: anonymous
        route: conditions
    - serviceBus:
      x-azure-settings:
        direction: out
        name: conditionsTopic
        topicName: condition-saved
        connection: ServiceBusConnection
  • What stacktrace or error message from your provider did you see?
    • function.json
{
  "disabled": false,
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "route": "conditions",
      "authLevel": "anonymous",
      "methods": [
        "POST"
      ]
    },
    {
      "type": "serviceBus",
      "direction": "out",
      "name": "conditionsTopic",
      "queueName": "outqueue",
      "topicName": "condition-saved",
      "connection": "ServiceBusConnection",
      "accessRights_": "Manage"
    }
  ],
  "entryPoint": "handler",
  "scriptFile": "..\\src\\handlers\\save-condition.js"
}
  • Microsoft.Azure.ServiceBus: Put token failebus.windows.net:outqueue, Timestamp:2019-09-30T16:35:11.ed. status-code: 404, status-description: The messaging entity 'sb://service-bus-name-here.servicebus.windows.net/outqueue' could not be found

Similar or dependent issues:

  • #57

Additional Data

  • Serverless Framework Version you're using:
    • 1.53.0
  • Serverless CLI Version you're using:
    • 1.2.3
  • Serverless Azure Plugin Version you're using:
    • 1.0.2-4
  • Operating System:
    • Windows 10
  • Stack Trace:
  • Provider Error messages:

stout01 avatar Sep 30 '19 16:09 stout01

Could you tell me what is the current status of this bug and when do you plan to fix this?

According to the Azure Servicebus output binding docs you can provide either queueName or topicName in function.json. If both of them are provided, then queue has bigger priority. That makes sending messages through out binding impossible for topic out binding. The only workaround that I have found so far is to create a queue that will forward those messages to topic but it seems to be too excessive.

I've taken a quick look into the source code and it seems that the problem lies in the missing ValidateIf logic for serviceBus out binding(required value is either queueName or topicName+ subscription). Also a quick fix might be probably done by changing true required flag in queueName and topicName for serviceBus in bindings.json. I am not sure why in the serviceBusTrigger those two values are false but as a consequence it may result in not having those values function.json unless they are provided in serverless.yml.

Nonetheless this issue is pretty serious and IMO should be fixed any time soon.

bartlomiejlazarczyk avatar Mar 11 '21 14:03 bartlomiejlazarczyk

I have the same issue. There is a workaround or fix?

majezanu avatar Mar 28 '21 05:03 majezanu

Hello, I have a workaround, I created a plugin with the following code:

'use strict';

const path = require('path');
const fs = require('fs');

class ServerlessPlugin {
  constructor(serverless, options) {
    this.serverless = serverless;
    this.options = options;

    this.hooks = {
      'after:package:setupProviderConfiguration': this.bindingCleanup.bind(this),
      'before:deploy:function:packageFunction': this.bindingCleanup.bind(this),
      'before:deploy:deploy': this.bindingCleanup.bind(this),
      'after:offline:build': this.bindingCleanup.bind(this),
    };
  }

  bindingCleanup() {
    this.serverless.cli.log('Hello from ServiceBus Binding Cleanup!');

    const parsedFunctions = this.serverless.service.getAllFunctions();
    
    parsedFunctions.forEach((parseFunction) => {
      this.serverless.cli.log('checking binding in -> ' + parseFunction);
      this.serverless.cli.log(this.serverless.config.servicePath);
      const functionJSON = JSON.parse(fs.readFileSync(path.join(this.serverless.config.servicePath, parseFunction,'function.json')).toString());
      const bindings = functionJSON.bindings;
      let update = false;
      bindings.forEach((binding, index) => {
        if (binding.queueName === false) {
          this.serverless.cli.log('    Found serviceBus with default queueName, updating ...');
          
          delete binding.queueName;

          functionJSON.bindings[index] = binding;
          update = true;
        }
      });
      if (update) {
        this.serverless.cli.log('    ... updated to ' + JSON.stringify(functionJSON));
        fs.writeFileSync(path.join(this.serverless.config.servicePath, parseFunction,'function.json'), JSON.stringify(functionJSON, null, 4));
      }
    });

    this.serverless.cli.log('All cleanup done, please check the binding in function.json!');
  }

}

module.exports = ServerlessPlugin;

With this, you only need to put queueName: false in your serverless.yml function

majezanu avatar Mar 30 '21 04:03 majezanu