无法使用预定的 firebase 功能从外部服务接收大 xml
Can not receive large xml from external service with scheduled firebase function
我正在使用 Typescript 作为后端语言,并安排了一个函数来从外部服务请求大 xml 文件 (75MB) 并对其进行解析。我必须设置一个 soap 客户端来接收 xml.
export const updateList: Function =
functions.region('europe-west3').pubsub.schedule('1 0 1 * *').onRun((_context) => {
const url = 'https://website.org';
const wsdl_options = {
ntlm: true,
username: 'username',
password: 'password',
domain: "domain",
workstation: "workstation"
};
soap.createClient(url, { wsdl_options }, (error, client) => {
if (error) {
console.log('Error in making soap client', error);
}
else {
client.setSecurity(new soap.NTLMSecurity(wsdl_options.username, wsdl_options.password, wsdl_options.domain));
const getXml = client.Service.HttpBinding_Service.GetXML;
try {
getXml((error, dataXml) => {
console.log('Inside xml');
if (error) {
console.log(error);
}
else {
console.log('...done.')
processData(dataXml);
}
});
} catch (error) {
console.log('Something wrong' + error);
}
}
})
});
调用 getXml 后停止。当从 PC 在本地调用相同的代码时,它运行良好并且接收 xml 并解析它所花费的时间不超过 20 秒。外部服务有 IP 白名单范围,因此添加了本地 WiFi 网络。我已经为 Firebase 功能设置了静态 IP 地址,并且外部服务提供商已将其添加到白名单 IP。我已经设置了 Cloud NAT、VPC 网络、无服务器 VPC 访问、VPC 连接器等
因此来自计划函数的流量正确地通过静态 IP 地址并且连接建立时没有错误,但它无法接收大 xml。
我试图获取 xml 5MB,它在调用该函数后 5 分钟后收到了它。 (我正在检查 firebase 函数中的控制台日志)
我该如何解决这个问题?有什么想法吗?
更新。在 20.06
上用完整代码更新了代码示例
正如所怀疑的那样,你已经正确地启动了函数,但是因为你没有返回一个 Promise
来“保持函数活动”,执行你的函数的实例被置于“非活动”状态其中网络请求被阻止并且 CPU 处理受到严重限制。因为您的系统不受如此激进的实例管理系统的约束,所以在本地开发时您不会看到类似的性能下降。重要的是,当您的函数处于“非活动”状态时,它可以随时终止,因此请确保在解析返回的 Promise
.
之前完成任何工作。
此行为在 in the documentation 及其链接视频中有更详细的介绍。
根据您的代码,您似乎正在使用 soap
package,它方便地同时具有基于回调和基于 Promise
的 API。这允许我们替换:
soap.createClient(url, { wsdl_options }, (error, client) => {
if (error) {
console.log("Error in making soap client", error);
} else {
// do something with client
}
});
只有
const client = await soap.createClientAsync(url, { wsdl_options });
// do something with client
利用这些基于 Promise
的 API,您的代码将类似于:
import * as functions from "firebase-functions";
import * as soap from "soap";
async function processData(data) {
// do something with data
}
export const updateList = functions
.region("europe-west3")
.pubsub.schedule("1 0 1 * *")
.onRun(async () => { // <- async added here
const url = "https://website.org";
const wsdl_options = {
ntlm: true,
username: "username",
password: "password",
domain: "domain",
workstation: "workstation",
};
const client = await soap.createClientAsync(url, { wsdl_options });
client.setSecurity(
new soap.NTLMSecurity({
username: wsdl_options.username,
password: wsdl_options.password,
domain: wsdl_options.domain
})
);
console.log("SOAP client initialized, obtaining XML data...");
const xmlData = await client.Service.HttpBinding_Service.GetXMLAsync();
// if the above isn't available, you could use:
// const xmlData = new Promise((resolve, reject) =>
// client.Service.HttpBinding_Service.GetXML(
// (err, result) => err ? reject(err) : resolve(result)
// )
// );
console.log("obtained XML data, now processing...");
await processData(xmlData);
console.log('Success!');
});
注意: 当我将它们拼凑在一起时,TypeScript 抛出了一个关于 NTLMSecurity
接受 3 个参数的错误,而它应该是一个单一的对象。所以上面改正了。
您可以在 this blog post or by checking out other questions here on Whosebug 中阅读有关 Promise 的更多信息。
我正在使用 Typescript 作为后端语言,并安排了一个函数来从外部服务请求大 xml 文件 (75MB) 并对其进行解析。我必须设置一个 soap 客户端来接收 xml.
export const updateList: Function =
functions.region('europe-west3').pubsub.schedule('1 0 1 * *').onRun((_context) => {
const url = 'https://website.org';
const wsdl_options = {
ntlm: true,
username: 'username',
password: 'password',
domain: "domain",
workstation: "workstation"
};
soap.createClient(url, { wsdl_options }, (error, client) => {
if (error) {
console.log('Error in making soap client', error);
}
else {
client.setSecurity(new soap.NTLMSecurity(wsdl_options.username, wsdl_options.password, wsdl_options.domain));
const getXml = client.Service.HttpBinding_Service.GetXML;
try {
getXml((error, dataXml) => {
console.log('Inside xml');
if (error) {
console.log(error);
}
else {
console.log('...done.')
processData(dataXml);
}
});
} catch (error) {
console.log('Something wrong' + error);
}
}
})
});
调用 getXml 后停止。当从 PC 在本地调用相同的代码时,它运行良好并且接收 xml 并解析它所花费的时间不超过 20 秒。外部服务有 IP 白名单范围,因此添加了本地 WiFi 网络。我已经为 Firebase 功能设置了静态 IP 地址,并且外部服务提供商已将其添加到白名单 IP。我已经设置了 Cloud NAT、VPC 网络、无服务器 VPC 访问、VPC 连接器等
因此来自计划函数的流量正确地通过静态 IP 地址并且连接建立时没有错误,但它无法接收大 xml。 我试图获取 xml 5MB,它在调用该函数后 5 分钟后收到了它。 (我正在检查 firebase 函数中的控制台日志)
我该如何解决这个问题?有什么想法吗?
更新。在 20.06
上用完整代码更新了代码示例正如所怀疑的那样,你已经正确地启动了函数,但是因为你没有返回一个 Promise
来“保持函数活动”,执行你的函数的实例被置于“非活动”状态其中网络请求被阻止并且 CPU 处理受到严重限制。因为您的系统不受如此激进的实例管理系统的约束,所以在本地开发时您不会看到类似的性能下降。重要的是,当您的函数处于“非活动”状态时,它可以随时终止,因此请确保在解析返回的 Promise
.
此行为在 in the documentation 及其链接视频中有更详细的介绍。
根据您的代码,您似乎正在使用 soap
package,它方便地同时具有基于回调和基于 Promise
的 API。这允许我们替换:
soap.createClient(url, { wsdl_options }, (error, client) => {
if (error) {
console.log("Error in making soap client", error);
} else {
// do something with client
}
});
只有
const client = await soap.createClientAsync(url, { wsdl_options });
// do something with client
利用这些基于 Promise
的 API,您的代码将类似于:
import * as functions from "firebase-functions";
import * as soap from "soap";
async function processData(data) {
// do something with data
}
export const updateList = functions
.region("europe-west3")
.pubsub.schedule("1 0 1 * *")
.onRun(async () => { // <- async added here
const url = "https://website.org";
const wsdl_options = {
ntlm: true,
username: "username",
password: "password",
domain: "domain",
workstation: "workstation",
};
const client = await soap.createClientAsync(url, { wsdl_options });
client.setSecurity(
new soap.NTLMSecurity({
username: wsdl_options.username,
password: wsdl_options.password,
domain: wsdl_options.domain
})
);
console.log("SOAP client initialized, obtaining XML data...");
const xmlData = await client.Service.HttpBinding_Service.GetXMLAsync();
// if the above isn't available, you could use:
// const xmlData = new Promise((resolve, reject) =>
// client.Service.HttpBinding_Service.GetXML(
// (err, result) => err ? reject(err) : resolve(result)
// )
// );
console.log("obtained XML data, now processing...");
await processData(xmlData);
console.log('Success!');
});
注意: 当我将它们拼凑在一起时,TypeScript 抛出了一个关于 NTLMSecurity
接受 3 个参数的错误,而它应该是一个单一的对象。所以上面改正了。
您可以在 this blog post or by checking out other questions here on Whosebug 中阅读有关 Promise 的更多信息。