How to fix "e.loadPromise.isResolved is not a function"
I have a couple of custom activities with Promises that so far return the correct information. For some reason, if the workflow runs long enough, I begin getting the following error:
Unhandled promise rejection TypeError: e.loadPromise.isResolved is not a function
Uncaught TypeError: e.loadPromise.isResolved is not a function
Even though I'm technically past my custom activities in the workflow and am able to log the results, I'm pretty sure they're the cause since I've used the remaining activities in other workflows. But once this error pops up, the workflow freezes and won't finish.
I've tried adding .catch() to the function chain to handle the "rejection" and a reject to the Promise itself, but I'm still getting errors.
Any ideas?
Current Code
async function getWorkbookFromBuffer(fileBuffer: Buffer): Promise<Excel.Workbook> {
const loader = new Excel.Workbook();
const workbook = await loader.xlsx.load(fileBuffer);
return workbook;
}
export default class GetWorkbookFromExcelBufferActivity implements IActivityHandler {
async execute(inputs: GetWorkbookFromExcelBufferInputs): Promise<GetWorkbookFromExcelBufferOutputs> {
const excelWorkbook = await getWorkbookFromBuffer(inputs.inputBuffer)
.then(result=>result)
.catch(err => {
console.log(err);
return "Error Getting Workbook from Buffer"
});
return {result: excelWorkbook}
}
}
-
Hi @Matthew Muehlhauser? ,
I don't think you can combine await and then() like that. I would suggest one or the other:
Using await:
try { const excelWorkbook = await getWorkbookFromBuffer(inputs.inputBuffer); return { result: excelWorkbook }; } catch (err) { console.log(err); return "Error Getting Workbook from Buffer"; }
Using then:
const myPromise = getWorkbookFromBuffer(inputs.inputBuffer) .then(excelWorkbook => {result: excelWorkbook}) .catch(err => { console.log(err); return "Error Getting Workbook from Buffer"; }); return myPromise;
As a side note, I'd recommend setting the error as a property on the result rather than returning an object sometimes and a string when there's an error.
0 -
@Ken Lyon? ,
Thanks for the advice Ken. I've switched to the try catch method, but that seems to result in the same issue. I'll keep playing around for now.
On the side note, how exactly would you add it as a property. I'm new to Typescript and as soon as I add the property, it starts screaming at me that the property doesn't exist in the output.
```js
return {result.error: "Get Workbook Error"}
```
0 -
See if you can find where you define the GetWorkbookFromExcelBufferOutputs interface. You should see that it has a result property, possibly like this:
export interface GetWorkbookFromExcelBufferOutputs { result: any; }
(You may have chosen a different type than "any".)
If you added an error property, it would look like this:
export interface GetWorkbookFromExcelBufferOutputs { result: any; /** Indicates the error if one was caught. */ error?: Error; }
The question mark means it's optional. It is allowed to be undefined when there is no error.
The data type is Error, which should work for anything you catch.
To return an error, you would do this:
try { // (other code here) } catch (err) { return { error: err }; }
0 -
@Ken Lyon?
To get that to work, I had to make the result optional as well and declare the type of err in the catch as any, but it seems to be happy.
That being said, I'm still getting the Promise.isResolved is not a function. It's just really confusing because my activity is working and the correct results are being logged to the console. So it's moved on, but somehow I feel like the promises or something are still sticking around.
I've been able to use the results in a query and pan to the features no problem, but if I try to add the "Show Results" activity, that's when I run into issues. It just runs forever and, other than those Promise errors, no Geocortex workflow specific errors show up in the console.
0 -
Ah, ok. I think it might be to do with the type of Promise being created. Unfortunately, there are different libraries that have been used over the years that don't all agree with each other. The isResolved() method is used by some but not others.
I'll see if I can find out more next week.
0 -
Hi @Matthew Muehlhauser? ,
I think that it might be necessary for your execute method to return a bluebird promise, rather than a native one. The tidiest place for this would be in your getWorkbookFromBuffer() method. you could return new Promise(workbook) after importing "bluebird" as Promise at the top of the file. This would create a bluebird promise based on the native one.
Could you provide any more details of the call stack that was associated with the error you saw? We are trying to remove our dependencies on bluebird and I'd like to fix that particular place so it's not necessary for custom activities in future.
0 -
I just did a small test by creating my own custom activity that returns a native Promise, and it ran without error in the sandbox. I'm thinking that you might be able to fix this without bluebird. I think you might just need to wrap the Excel promise in a native one:
async function getWorkbookFromBuffer(fileBuffer: Buffer): Promise<Excel.Workbook> { const loader = new Excel.Workbook(); return new Promise(loader.xlsx.load(fileBuffer)); }
0 -
@Ken Lyon?
I had to add the resolve callback function for it to be ok, so my function now looks like this:
async function getWorkbookFromBuffer(fileBuffer: Buffer): Promise<Excel.Workbook> {
return new Promise((resolve) => {
const loader = new Excel.Workbook();
resolve(loader.xlsx.load(fileBuffer));
})
}
However; it's still giving me the error. I'm wondering now though if maybe these two workflows aren't the problem.
I have another workflow which takes the workbook from the previous and basically just filters out the information that I'm looking for. It has no Promises and the default class export's execute isn't async. Should I try converting that into a promise?
export default class GetRollsFromWorkbookActivity implements IActivityHandler {
execute(inputs: GetRollsFromWorkbookInputs): GetRollsFromWorkbookOutputs {
let rollList: Array<string> = [];
const regex = /^\d{9}$/gm;
inputs.workbook.worksheets.forEach(sheet => {
sheet.columns.forEach(column => {
if (column.values) {
const arrayValues: Array<string> = column.values.filter(value => {
return (typeof(value)==="string" && regex.test(value))
}) as Array<string>
if (arrayValues) {rollList = [...rollList, ...arrayValues]}
}
})
})
return {result: rollList}
}
}
0 -
So, I tried changing that one to an async workflow as well, but it's a no go. It still ends up with the same issue.
0 -
@Ken Lyon? Oh, and for the error call stack, I'm assuming you mean the errors in the browser. I've attached some photos of the errors I get. There's a few more that pop up if I let it run long enough, but they're pretty much the same.
Also, is there any documentation for formatting text in this forum?
0 -
@Matthew Muehlhauser? ,
Thanks for the screenshot. That is helpful. It looks like you're running this in Geocortex Viewer for HTML5. Is that correct? Could you try running the workflow in the Designer Sandbox? I'd be interested to see if the same problem occurs there, or only in the viewer.
The other custom activity does not need to be changed to use promises. An activity only needs to return a promise if it includes an asynchronous operation.
We don't have any documentation for formatting text in the forum. You can click the "Code Snippet" button (that looks like </>) and then paste code in there for it to be shown as source code. We're really limited to the buttons on that toolbar.
0 -
@Ken Lyon?
Hmmm, I just had to add an extra projectGeometry to the workflow and hardcode some urls, but it's worked.
The only thing is the Show Results didn't show any results since there's no attribute table widget in the sandbox. My current workflow works if I take out the Show Results as well though. I did get an info warning in my current map without the Show Results activity saying:
Error encountered attempting to project geometry: TypeError: Promise.map is not a function
But everything ran fine. So, I've tried hardcoding the Query Layer with the results from the custom activities and plugged that into the Show Results and I still got that error. However; I still had the Custom Activities in the workflow but they just weren't connected. When I removed the Custom Activities from the workflow entirely, everything worked fine.
Also, I don't have a Code Snippet button.
0 -
I also tried using blue bird:
import * as Promise from "bluebird";
But I'm still getting the same errors.
0 -
Hi @Matthew Muehlhauser? ,
Thanks for the update. I discussed this issue with a colleague in the Geocortex Viewer for HTML5 team. He thinks the problem might be to do with something else entirely.
When we look at the stack traces from your screenshot, it seems like the viewer is trying to determine which modules can be loaded. This isn't related to your activity. For example, Geocortex Workflow itself is a module within the viewer.
The promise mentioned in the error message is probably not the one returned by your custom activity.
0 -
Hey @Ken Lyon? ,
So, out of curiosity, I tried to build the activities and host them on the server to see if it would help at all, but I'm still getting the same error.
I knew it was a long shot, but just trying to see if anything will help.
0 -
@Ken Lyon?
Tried something new. I ran a query before running the task to try to load up some modules that may be causing it to take longer. Now, instead of a Promise.isResolved is not a function, I get a Promise.delay is not a function.
0 -
Hi @Matthew Muehlhauser?. I took a look at your stack traces, and they seem to be indicating some sort of issue with deferred module loading. This may be a red herring though, as I don't immediately see what the connection with your custom code would be here.
To rule this out, please take a look at the top of your json config file for this viewer (desktop.json.js etc...). You should see something like this:
{ "configuration": { "version": "4.14", "application": { "proxyUri": "proxy.ashx?", "allowUnsafeContent": false, "deferredModuleLoading": true, ...
Please change "deferredModuleLoading" to false and see if that has any effect on your issue. You can revert back afterwards if it does not, as the error messages are not necessarily indicating something to be concerned about if they are not actually related to the problem.
0 -
@Jonathan Bystedt?
Hmm, still getting the Promise.delay is not a function errors. There's also one Promise.map is not a function at the very end.
0 -
It's possible that the failure is happening later in the workflow with another activity that uses the result of your custom activity. If you turn on verbose logging, the console should show you where you got to when things went wrong.
0 -
@Ken Lyon?
I don't think that's the case. I had one large custom activity at first, but now have it broken into three to see if that would help. The final one returns an array that I use to create the Where Clause in the Query Task. I can log the feature results of the query task just fine. I can even pan to the results. But, as soon as I add in the Show Results activity, it starts to give me errors. Which also doesn't really make sense, because the results being passed into that aren't even from the custom activities which should be out of the picture by this point.
Now, I think I still get some errors when I take out the show results activity, but it doesn't freeze or get held up like it currently does.
0 -
@Ken Lyon?
Here are the results from the verbose logging.
0 -
Thanks for that. I have a few questions now...
- Did the error occur on this run?
- Is Set View Extent the last activity in the workflow?
The logging shows that each of the activities did finish. Entries starting with "--->" are just before an activity is executed, and those ending with "--->" are just after it has finished. You can also see that in each case the outputs property changes from undefined to an object.
0 -
@Ken Lyon?
Yes and Yes.
When it gets hung up, that's when the first 40 Violations show up and nothing works anymore. When I refresh the page, that's when the rest of the Violations show up including the unload and load handlers.
Below is showing the results table. The correct parcels have been selected and zoomed to in the map, but it just will not finish showing the results. I didn't realize, but with loading all the modules now, the map is still responsive and I can run other workflows, it just doesn't ever load the results in the results pane.
0 -
@Ken Lyon? @Jonathan Bystedt?
Not sure if this helps at all, but this is the line that's failing:
n.raceAll = function(r, e, n) {
return Promise.all(r.map(function(r) {
return Promise.race([r.catch(function(r) {
return n
}), Promise.delay(e, n)]) //Promise.delay method doesn't exist
}))
}
And that's within the:
"geocortex/infrastructure/PromiseUtils"
My understanding is that .delay is a bluebird Promise method, so just to make sure, I made sure I was importing the Bluebird Promises, but I'm still getting an error.
0 -
Hi @Matthew Muehlhauser? ,
It seems this issue is going to take a bit more investigation to be able to find the cause. We've logged this bug in our backlog. When referring to it in future please quote Bug #47704.
We will be in touch if we need further details.
0 -
@Ken Lyon?
Thanks Ken. Let me know if you need anything like the build files or the source code!
0
Du måste logga in om du vill lämna en kommentar.
Kommentarer
26 kommentarer