Azure 应用服务Azure JS Function 异步方法中执行SQL查询后,Callback函数中日志无法输出问题

Posted 云中一盏灯,路边形影重

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Azure 应用服务Azure JS Function 异步方法中执行SQL查询后,Callback函数中日志无法输出问题相关的知识,希望对你有一定的参考价值。

Warning: Unexpected call to \'log\' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to \'done\' made before function execution completes. The context.done method is deprecated,Now, it\'s recommended to remove the call to context.done() and mark your function as async so that it returns a promise (even if you don\'t await anything).

问题描述

开发 Azure JS Function(NodeJS),使用 mssql 组件操作数据库。当SQL语句执行完成后,在Callback函数中执行日志输出 context.log(" ...") , 遇见如下错误:

Warning: Unexpected call to \'log\' on the context object after function execution has completed.

Please check for asynchronous calls that are not awaited or calls to \'done\' made before function execution completes. 

Function name: HttpTrigger1. Invocation Id: e8c69eb5-fcbc-451c-8ee6-c130ba86c0e9. Learn more: https://go.microsoft.com/fwlink/?linkid=2097909

错误截图

 

问题解答

JS 函数代码(日志无法正常输出)

var sql = require(\'mssql\');
var config = 
    user: \'username\',
    password: \'Password\',
    server: \'<server name>.database.chinacloudapi.cn\', // You can use \'localhost\\\\instance\' to connect to named instance
    database: \'db name\',

    options: 
        encrypt: true // Use this if you\'re on Windows Azure
    

module.exports
= async function (context, req) context.log(\'JavaScript HTTP trigger function processed a request.\'); await callDBtoOutput(context); context.log(\'################\'); //Default Code ... const name = (req.query.name || (req.body && req.body.name)); const responseMessage = name ? "Hello, " + name + ". This HTTP triggered function executed successfully." : "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."; context.res = // status: 200, /* Defaults to 200 */ body: responseMessage ; async function callDBtoOutput(context) try context.log("Some Message from callDBtoOutput") var ps = new sql.PreparedStatement(await sql.connect(config)) await ps.prepare(\'SELECT SUSER_SNAME() \', async function (err) if (err) context.log(err) context.log("start to exec sql ...from callDBtoOutput") await ps.execute(, async function (err, recordset) // ... error checks context.log(recordset) context.log("Login SQL DB successfully....from callDBtoOutput") ps.unprepare(function (err) // ... error checks ); ); ); catch (error) context.log(`Some Error Log: from callDBtoOutput`, error);

在 callDBtoOutput() 函数中,调用sql prepare 和 execute方法执行sql语句,虽然已经使用了async和await关键字,但根据测试结果表明:Function的主线程并不会等待callback函数执行。当主线程中context对象释放后,子线程中继续执行context.log函数时就会遇见以上警告信息。 

 

为了解决以上prepare和execute方法中日志输出问题,需要使用其他执行sql的方法。在查看mssql的官方说明(https://www.npmjs.com/package/mssql#query-command-callback)后,发现query方法能够满足要求。

query (command, [callback])

Execute the SQL command. To execute commands like create procedure or if you plan to work with local temporary tables, use batch instead.

Arguments

  • command - T-SQL command to be executed.
  • callback(err, recordset) - A callback which is called after execution has completed, or an error has occurred. Optional. If omitted, returns Promise.

 

经过多次测试,以下代码能完整输出Function过程中产生的日志。

JS 函数执行SQL代码(日志正常输出)

var sql = require(\'mssql\');

var config = 
    user: \'username\',
    password: \'Password\',
    server: \'<server name>.database.chinacloudapi.cn\', // You can use \'localhost\\\\instance\' to connect to named instance
    database: \'db name\',

    options: 
        encrypt: true // Use this if you\'re on Windows Azure
    


module.exports = async function (context, req) 
    context.log(\'JavaScript HTTP trigger function processed a request.\');
    
    // context.log(\'call callDBtoOutput 1\');
    // await callDBtoOutput(context);

    //context.log(\'call callDBtoOutput 2\');
    await callDBtoOutput2(context);

    context.log(\'################\');
    const name = (req.query.name || (req.body && req.body.name));
    const responseMessage = name
        ? "Hello, " + name + ". This HTTP triggered function executed successfully."
        : "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.";

    context.res = 
        // status: 200, /* Defaults to 200 */
        body: responseMessage
    ;


async function callDBtoOutput2(context) 
    context.log("1: Call SQL Exec function ....")
    await sql.connect(config).then(async function () 
        // Query
        context.log("2: start to exec sql ... ")     
        await new sql.Request().query(\'SELECT SUSER_SNAME() \').then(async function (recordset) 
            context.log("3: Login SQL DB successfully.... show the Query result") 
            context.log(recordset);

        ).catch(function (err) 
            // ... error checks
        );
    )
    context.log("4: exec sql completed ... ") 

结果展示(完整日志输出)

 

参考资料

node-mssql: https://www.npmjs.com/package/mssql

context.done : https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node?pivots=nodejs-model-v3&tabs=javascript%2Cwindows-setting-the-node-version#contextdone

The context.done method is deprecated

Now, it\'s recommended to remove the call to context.done() and mark your function as async so that it returns a promise (even if you don\'t await anything).

在 Microsoft Azure 应用服务上部署 Next.js 应用

【中文标题】在 Microsoft Azure 应用服务上部署 Next.js 应用【英文标题】:Deploying Next.js App on Microsoft Azure App Service 【发布时间】:2019-08-14 18:52:35 【问题描述】:

我正在尝试在 Azure 应用服务上部署一个非常简单的 Next.js 应用。运行“npm run build”后,我使用 azure Visual Studio Code 扩展来完成部署。

这个过程是成功的,如果我通过 FTP 连接到我的应用服务,我可以看到 wwwroot 目录中的文件。

但如果我尝试浏览应用程序,我会收到“应用程序错误” 如果您是应用程序管理员,则可以访问诊断资源。'

访问诊断,这是我看到的消息:

48:17.620204936Z Generating app startup command
2019-03-24T08:48:17.635158983Z Found scripts.start in /home/site/wwwroot/package.json
2019-03-24T08:48:17.649648532Z Running npm --prefix=/home/site/wwwroot start
2019-03-24T08:48:18.702111743Z 
2019-03-24T08:48:18.702164243Z > macingo.admin@1.0.0 start /home/site/wwwroot
2019-03-24T08:48:18.702170943Z > next start
2019-03-24T08:48:18.702174443Z 
2019-03-24T08:48:18.791276730Z /home/site/wwwroot/node_modules/.bin/next: line 1: ../next/dist/bin/next: not found

消息很清楚,但我不确定我做错了什么。这是我第一次尝试在 Azure 上部署基于 node.js 的应用程序。 任何帮助将不胜感激!

/home/site/wwwroot/node_modules/next/dist/bin/next

【问题讨论】:

检查your_app_folder/node_modules/next/dist/bin/next是否存在 @evgenifotia 只是仔细检查了一遍,我可以确认它存在于 node_modules 下。看起来,从上面的消息来看,它正试图从这里寻找它:'/home/site/wwwroot/node_modules/.bin/next'。 不,/home/site/wwwroot/node_modules/.bin/next 中有一段代码执行../next/dist/bin/next 你确定/home/site/wwwroot/node_modules/next/dist/bin/next存在吗? 请参考youtube.com/watch?v=Ut8KYyCOqpA&t=2s 【参考方案1】:

我遇到了同样的错误,并在这个问题中找到了解决方案:unable to deploy next js to azure

似乎 Azure 的 next start 命令存在问题,需要使用 server.js。所以我做了什么让它运行:

根据下一个文档创建server.js 文件:https://nextjs.org/docs/advanced-features/custom-server 并更新 server.js 文件,使其使用环境变量中的端口:
const  createServer  = require("http");
const  parse  = require("url");
const next = require("next");

const dev = process.env.NODE_ENV !== "production";
const app = next( dev );
const handle = app.getRequestHandler();

const port = process.env.PORT || 3000;

app.prepare().then(() => 
  createServer((req, res) => 
    // Be sure to pass `true` as the second argument to `url.parse`.
    // This tells it to parse the query portion of the URL.
    const parsedUrl = parse(req.url, true);
    const  pathname, query  = parsedUrl;

    if (pathname === "/a") 
      app.render(req, res, "/a", query);
     else if (pathname === "/b") 
      app.render(req, res, "/b", query);
     else 
      handle(req, res, parsedUrl);
    
  ).listen(port, (err) => 
    if (err) throw err;
    console.log("> Ready on http://localhost:", port);
  );
);
更新 package.json 脚本:
"dev": "node server.js",
"build": "next build",
"start": "node server.js"
添加web.config 文件(如post 中所述:
<?xml version="1.0" encoding="utf-8"?>
<!--
     This configuration file is required if iisnode is used to run node processes behind
     IIS or IIS Express.  For more information, visit:
     https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
-->

<configuration>
  <system.webServer>
    <!-- Visit http://blogs.msdn.com/b/windowsazure/archive/2013/11/14/introduction-to-websockets-on-windows-azure-web-sites.aspx for more information on WebSocket support -->
    <webSocket enabled="false" />
    <handlers>
      <!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
      <add name="iisnode" path="server.js" verb="*" modules="iisnode"/>
    </handlers>
    <rewrite>
      <rules>
        <!-- Do not interfere with requests for node-inspector debugging -->
        <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
          <match url="^server.js\/debug[\/]?" />
        </rule>

        <!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
        <rule name="StaticContent">
          <action type="Rewrite" url="publicREQUEST_URI"/>
        </rule>

        <!-- All other URLs are mapped to the node.js site entry point -->
        <rule name="DynamicContent">
          <conditions>
            <add input="REQUEST_FILENAME" matchType="IsFile" negate="True"/>
          </conditions>
          <action type="Rewrite" url="server.js"/>
        </rule>
      </rules>
    </rewrite>

    <!-- 'bin' directory has no special meaning in node.js and apps can be placed in it -->
    <security>
      <requestFiltering>
        <hiddenSegments>
          <remove segment="bin"/>
        </hiddenSegments>
      </requestFiltering>
    </security>

    <!-- Make sure error responses are left untouched -->
    <httpErrors existingResponse="PassThrough" />

    <!--
      You can control how Node is hosted within IIS using the following options:
        * watchedFiles: semi-colon separated list of files that will be watched for changes to restart the server
        * node_env: will be propagated to node as NODE_ENV environment variable
        * debuggingEnabled - controls whether the built-in debugger is enabled
      See https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config for a full list of options
    -->
    <!--<iisnode watchedFiles="web.config;*.js"/>-->
  </system.webServer>
</configuration> 

【讨论】:

以上是关于Azure 应用服务Azure JS Function 异步方法中执行SQL查询后,Callback函数中日志无法输出问题的主要内容,如果未能解决你的问题,请参考以下文章

通过 Azure 从 node.js 发送推送通知

无法在 Azure mySQL 中创建函数/存储过程

Azure 应用服务静态 URL 案例更改

使用 Github Actions 将 Next.js 部署到 Azure 应用服务的问题

在 Microsoft Azure 应用服务上部署 Next.js 应用

Azure 移动应用 Node.js 后端 - 推送通知错误状态代码 400