我对 javascript 中的持久函数 V4 很陌生,但我无法让此活动正常运行。我总是收到错误,因为显然我没有正确传递实例 ID。
我在这里做错了什么?微软网站上的教程页面没有用。
这是代码:
df.app.orchestration('reportOrchestrator', function* (context) {
try {
const instanceId = context.df.instanceId; // Get the current orchestration's instance ID
context.log(`Orchestration instance ID: ${instanceId}`);
const lsFile = { instanceID: instanceId }; // Pass instanceID in an object
const token = yield context.df.callActivity('TokenManager', { instanceID: instanceId });
context.log(`Token retrieved: ${token}`);
return token;
// const result = yield context.df.callActivity('PipelineQuery', { token });
} catch (error) {
return error.message;
context.log(`Error in orchestration: ${error.message}`);
throw error;
}
});
df.app.activity('TokenManager', {
handler: async (context) => {
const log = context.log;
const lsFile = context.getClient().instanceID; // Direct input passed from the orchestrator
if (!lsFile || !lsFile.instanceID) {
//log("InstanceID is missing or undefined");
throw new Error("InstanceID is missing or undefined,", context);
}
const instanceID = lsFile;
//log(`Orchestrator Instance ID is ${instanceID}`);
let functionID = "POST Reports Orchestrator";
try {
// Make the POST request to retrieve the token
const tokenResponse = await axios.post(logicAppURL, {
requestType: "GET_TOKEN",
functionID: functionID,
});
// Check if token was successfully retrieved
if (tokenResponse.data && tokenResponse.data.token) {
//log("Token successfully retrieved");
return tokenResponse.data.token;
} else {
//log("Token could not be retrieved. Functions will generate their own token");
await mandrillGeneralError(log, "Error retrieving token on POST Reports Orchestrator Token Manager function app in Azure.");
return ""; // Return empty token if retrieval fails
}
} catch (error) {
//log(`Error retrieving token: ${error.message}`);
await mandrillGeneralError(log, `Error retrieving token: ${error.message}`);
throw error; // Throw the error so it's logged properly by Durable Functions
}
}
});
我尝试了你的代码并得到了同样的错误:
incorrect Instance ID
。
发生这种情况是因为
instance ID
每次运行时都会发生变化。 instance ID
是实例的唯一标识符,如果您不指定此参数,该方法将使用随机 ID。
我已参考此文档了解 JavaScript 中的持久函数
下面的代码用于检索持久函数中的令牌,并通过此 git 链接获取完整代码。
const axios = require('axios');
async function generateToken(logicAppURL, instanceID) {
if (!instanceID) {
throw new Error("InstanceID is missing or undefined.");
}
console.log(`Orchestrator Instance ID is ${instanceID}`);
try {
const tokenResponse = await axios.post(logicAppURL, {
// requestType: "GET_TOKEN", // Uncomment and customize if needed
// functionID: functionID, // Uncomment and customize if needed
});
if (tokenResponse.data && tokenResponse.data.token) {
console.log("Token successfully retrieved");
return tokenResponse.data.token;
} else {
console.log("Token could not be retrieved. Returning an empty token.");
return "";
}
} catch (error) {
console.error(`Error retrieving token: ${error.message}`);
throw error;
}
}
const logicAppURL = "<Your Logic App URL>";
const instanceID = "your-instance-id";
generateToken(logicAppURL, instanceID)
.then(token => console.log(`Generated Token: ${token}`))
.catch(error => console.error(error));
输出:
我参考了这个git来传递和处理参数持久函数。
在您的代码中,我看到
logicAppURL
(或)anyURl
使用 post /get
请求,将实例 ID 传递给名为 TokenManager
和 FunctionId
的活动函数。
一般来说,如果实例 ID 每次都更改,则不要使用实例 ID 作为参数,并且
FunctionId
属性为 Azure Function 提供唯一标识符,该标识符由主机分配。
module.exports = async function (context, req) {
const functionId = context.executionContext.functionName;
context.log(`Function ID: ${functionId}`);
此标识符在同一函数的多次调用中保持稳定,从而实现一致的跟踪和记录。
const invocationId = context.executionContext.invocationId;
context.log(`Invocation ID: ${invocationId}`);
另外,参考这个SO获取逻辑应用的标识符,并在传入post请求时检查上面的字段。
另一种方法是仅使用logicAppURL请求中的url进行post/get请求,而不使用functionID、Instance ID。
我已参考链接从逻辑应用程序获取令牌。
const axios = require('axios');
const { app } = require('@azure/functions');
const df = require('durable-functions');
const tenantId = 'tenantId';
const clientId = 'clientId';
const clientSecret = 'clientSecret';
async function getAccessToken() {
const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
const params = new URLSearchParams();
params.append('grant_type', 'client_credentials');
params.append('client_id', clientId);
params.append('client_secret', clientSecret);
params.append('scope', 'https://management.azure.com/.default');
try {
const response = await axios.post(url, params, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
const accessToken = response.data.access_token;
console.log('Access Token:', accessToken);
return accessToken;
} catch (error) {
console.error('Error retrieving access token:', error.response ? error.response.data : error.message);
}
}
const activityName = 'durableHello1';
df.app.orchestration('durableHello1Orchestrator', function* (context) {
const input = context.df.getInput();
const outputs = [];
const accessToken = yield context.df.callActivity('getAccessTokenActivity', null);
for (const city of input.cities || ['Tokyo']) {
outputs.push(yield context.df.callActivity(activityName, city));
}
return { greetings: outputs, accessToken };
});
df.app.activity(activityName, {
handler: (input) => {
return `Hello, ${input}`;
},
});
df.app.activity('getAccessTokenActivity', {
handler: async () => {
return await getAccessToken();
},
});
app.http('durableHello1HttpStart', {
route: 'orchestrators/{orchestratorName}',
extraInputs: [df.input.durableClient()],
handler: async (request, context) => {
const client = df.getClient(context);
const body = await request.json();
const instanceId = await client.startNew(request.params.orchestratorName, undefined, body);
context.log(`Started orchestration with ID = '${instanceId}'.`);
return client.createCheckStatusResponse(request, instanceId);
},
});