Why does my findOne query hang indefinitely? - strapi

I just created a new project [GitHub] with yarn create strapi-app to test model lifecycle methods. I'm making a write-once read-many field called number_of_onsite_lessons.
I want to have a field where a user can specify how many Onsine Lessons should be generated when creating an Onsite Course and then disable that field - or at least throw an error when they try to change its value.
To this end, I wrote a lifecycle method of OnsiteCourse:
// Before updating a value.
// Fired before an `update` query.
beforeUpdate: async (model, attrs, options) => {
const prev = await strapi.query("onsite-course").findOne({_id: model.id});
console.log(prev,model);
if (prev.number_of_onsite_lessons != model.number_of_onsite_lessons) {
throw new Error("Can't change number of lessons - delete or create onsite lessons instead.")
}
if (prev.number_of_onsite_projects != model.number_of_onsite_projects) {
throw new Error("Can't change number of projects - delete or create onsite projects instead.")
}
},
When I update an OnsiteCourse entity, the code runs, but it stops at await strapi.query("onsite-course").findOne({...}) and then hangs indefinitely. I don't get an error, nor do I get that console.log on the next line.
After a while, this error shows up in the console:
[2020-03-17T07:42:30.558Z] error TimeoutError: Knex: Timeout acquiring a connection. The pool is probably full. Are you missing a .transacting(trx) call?
at Bluebird.try.then.catch (/home/teri/projects/strapi/new/node_modules/knex/lib/client.js:318:17)
at tryCatcher (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/util.js:16:23)
at /home/teri/projects/strapi/new/node_modules/bluebird/js/release/catch_filter.js:17:41
at tryCatcher (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/util.js:16:23)
at Promise._settlePromiseFromHandler (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/promise.js:547:31)
at Promise._settlePromise (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/promise.js:604:18)
at Promise._settlePromise0 (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/promise.js:649:10)
at Promise._settlePromises (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/promise.js:725:18)
at _drainQueueStep (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/async.js:93:12)
at _drainQueue (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/async.js:86:9)
at Async._drainQueues (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/async.js:102:5)
at Immediate.Async.drainQueues [as _onImmediate] (/home/teri/projects/strapi/new/node_modules/bluebird/js/release/async.js:15:14)
at processImmediate (internal/timers.js:443:21)

I got the same issues using sqlite connector (with 3.0.0-beta.20)
// tryed on beforeCreate, beforeUpdate and beforeSave
await strapi.query("product").findOne({ id: 1 })
await strapi.api.product.services.product.findOne({ id: 1 })
await strapi.api.product.controllers.product.findOne({ params: { id: 1 } })
await strapi.services.product.findOne({ id: 1 })
solved by using mongodb (mysql and others should work too !)

Related

Maximum call stack size exceeded on GraphQL Upload with NestJS

I'm facing an error on file upload with GraphQL Upload using the ReadStream function:
error: 17:10:32.466+02:00 [ExceptionsHandler] Maximum call stack size exceeded
error: 17:10:32.467+02:00 [graphql] Maximum call stack size exceeded RangeError: Maximum call stack size exceeded
at ReadStream.open (/Users/xxxx/Documents/Xxxx/xxxxx/xxxxx-api/node_modules/fs-capacitor/lib/index.js:80:7)
at _openReadFs (internal/fs/streams.js:117:12)
at ReadStream.<anonymous> (internal/fs/streams.js:110:3)
at ReadStream.deprecated [as open] (internal/util.js:96:15)
at ReadStream.open (/Users/xxxx/Documents/Xxxxx/xxxx/xxxxx-api/node_modules/fs-capacitor/lib/index.js:90:11)
at _openReadFs (internal/fs/streams.js:117:12)
at ReadStream.<anonymous> (internal/fs/streams.js:110:3)
at ReadStream.deprecated [as open] (internal/util.js:96:15)
at ReadStream.open (/Users/xxxx/Documents/Xxxxx/xxxxx/xxxxx-api/node_modules/fs-capacitor/lib/index.js:90:11)
at _openReadFs (internal/fs/streams.js:117:12) {"stack":"RangeError: Maximum call stack size exceeded\n at ReadStream.open (/Users/xxxx/Documents/Xxxxxx/xxxxx/xxxx-api/node_modules/fs-capacitor/lib/index.js:80:7)\n at _openReadFs (internal/fs/streams.js:117:12)\n at ReadStream.<anonymous> (internal/fs/streams.js:110:3)\n at ReadStream.deprecated [as open] (internal/util.js:96:15)\n at ReadStream.open (/Users/xxxxx/Documents/Xxxxx/xxxxx/xxxxx-api/node_modules/fs-capacitor/lib/index.js:90:11)\n at _openReadFs (internal/fs/streams.js:117:12)\n at ReadStream.<anonymous> (internal/fs/streams.js:110:3)\n at ReadStream.deprecated [as open] (internal/util.js:96:15)\n at ReadStream.open (/Users/xxxx/Documents/Xxxxxx/xxxx/xxxxx-api/node_modules/fs-capacitor/lib/index.js:90:11)\n at _openReadFs (internal/fs/streams.js:117:12)"}
(node:44569) [DEP0135] DeprecationWarning: ReadStream.prototype.open() is deprecated
(Use `node --trace-deprecation ...` to show where the warning was created)
Here is the function I'm using to upload a file:
public async cleanUpload(upload: GraphqlUpload, oldName?: string) {
let uploadResponse: FileInfo;
try {
if (oldName) {
this.safeRemove(oldName);
}
uploadResponse = await this.uploadFile(
{
fileName: upload.filename,
stream: upload.createReadStream(),
mimetype: upload.mimetype,
},
{ isPublic: true, filter: imageFilterFunction },
);
return uploadResponse;
} catch (e) {
this.logger.error('unable to upload', e);
if (uploadResponse) {
this.safeRemove(uploadResponse.fileName);
}
throw e;
}
}
The solution was to downgrade the Node version to 12.18 from 14.17.
To keep using Node 14.17 what you can do is to disable Apollo's internal upload and use graphql-upload
Please see this comment which outline the approach quoted here.
For any future readers, here is how to fix the issue once and for all.
The problem is that #nestjs/graphql's dependency, apollo-server-core, depends on an old version of graphql-upload (v8.0) which has conflicts with newer versions of Node.js and various packages. Apollo Server v2.21.0 seems to have fixed this but #nestjs/graphql is still on v2.16.1. Furthermore, Apollo Server v3 will be removing the built-in graphql-upload.
The solution suggested in this comment is to disable Apollo Server's built-in handling of uploads and use your own. This can be done in 3 simple steps:
1. package.json
Remove the fs-capacitor and graphql-upload entries from the resolutions section if you added them, and install the latest version of graphql-upload (v11.0.0 at this time) package as a dependency.
2. src/app.module.ts
Disable Apollo Server's built-in upload handling and add the graphqlUploadExpress middleware to your application.
import { graphqlUploadExpress } from "graphql-upload"
import { MiddlewareConsumer, Module, NestModule } from "#nestjs/common"
#Module({
imports: [
GraphQLModule.forRoot({
uploads: false, // disable built-in upload handling
}),
],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(graphqlUploadExpress()).forRoutes("graphql")
}
}
3. src/blog/post.resolver.ts (example resolver)
Remove the GraphQLUpload import from apollo-server-core and import from graphql-upload instead
// import { GraphQLUpload } from "apollo-server-core" <-- remove this
import { FileUpload, GraphQLUpload } from "graphql-upload"
#Mutation(() => Post)
async postCreate(
#Args("title") title: string,
#Args("body") body: string,
#Args("attachment", { type: () => GraphQLUpload }) attachment: Promise<FileUpload>,
) {
const { filename, mimetype, encoding, createReadStream } = await attachment
console.log("attachment:", filename, mimetype, encoding)
const stream = createReadStream()
stream.on("data", (chunk: Buffer) => /* do stuff with data here */)
}

Receiving error: Class Action is missing in schema: actions.actions

I'm trying to broadcast transaction having following actions:
actions: [
transactions.createAccount(),
transactions.transfer(new BN(swapParams.value.toFixed())),
transactions.deployContract(new Uint8Array(bytecode)),
transactions.functionCall(
ABI.init.method,
{
secretHash: Buffer.from(swapParams.secretHash, 'hex').toString('base64'),
expiration: `${toNearTimestampFormat(swapParams.expiration)}`,
buyer: swapParams.recipientAddress
},
new BN(ABI.init.gas),
new BN(0)
)
]
But when I invoke
const tx = await from.signAndSendTransaction(addressToString(options.to), options.actions)
I receive following callstack:
Any idea what might be the reason?
I'm using:
near-js-api: 0.39.0
According to the documentation, source code, and defined types signAndSendTransaction should take a single argument (an object with receiverId and actions fields):
const tx = await from.signAndSendTransaction({
receiverId: addressToString(options.to),
actions: options.actions
})
Was there an example/doc that mislead you, so you arrived with this function call interface? We should fix that.

NestJS: Problem with using ResolveProperty. Got " UnhandledPromiseRejectionWarning: TypeError:"

I have the parent model (camera) that contains the id of child (conveyor) as shown below:
#ObjectType('camera')
export class CameraModel {
#Field(() => ID)
_id: String;
#Field()
name: String;
#Field(() => ConveyorModel)
conveyor: ConveyorModel;
}
So in order to get detail of "conveyor" i need to use #ResolveProperty decorator in camera.resolver.ts (note: showing only related method)
import { CameraModel } from './models/camera.model';
import { ConveyorService } from "../conveyor/conveyor.service";
import { ConveyorModel } from "../conveyor/models/conveyor.model";
#Injectable()
export class CameraResolver {
constructor(
private conveyorService: ConveyorService,
private cameraService: CameraService,
) {}
#ResolveProperty('conveyor', type => ConveyorModel)
async getConveryor(#Parent() CameraModel) {
const { cid } = CameraModel;
return this.conveyorService.findOne(cid);
}
}
I got below error after run the server. Mostly from the graphql schema generator.
(node:30636) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'getObjectType' of undefined
...
(node:30636) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:30636) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
However if i comment out the #ResolveProperty block, everything went fine. But i can't just get detail of the conveyor (only get ID).
What am I missing here?
Based on my finding related issues at https://github.com/nestjs/graphql/issues/158
It has been fixed.
Don't use string base decorator of #Resolver('YourModel'). Just use #Resolver(of => YourModel);
The document of NestJS in this part is really insufficient.

Error on returning environmental account id's

If I have the following method to test predecessor_account_id behaviour
pub fn get_pred_acc(&self) -> (String {
let prev_acc = env::predecessor_account_id().to_string();
return prev_acc;
}
And try to call this from frontend
const contract = await this.near.loadContract(window.nearConfig.contractName, {
viewMethods: ["get_pred_acc", ],
changeMethods: [],
sender: this.accountId,
});
const acc = await contract.get_pred_acc();
I get the following error:
Uncaught (in promise) Error: Querying call/flux-protocol/get_account_id failed: wasm execution failed with error: FunctionCallError(HostError(ProhibitedInView("predecessor_account_id"))).
{ "error": "wasm execution failed with error: FunctionCallError(HostError(ProhibitedInView(\"predecessor_account_id\")))",
"logs": []
}
That's expected behavior for the view calls.
The view calls don't have certain context information such calls are not part of an actual transaction.
Currently, the best option to see which methods are prohibited in the view calls is to take a look at the test: https://github.com/nearprotocol/nearcore/blob/master/runtime/near-vm-logic/tests/test_view_method.rs#L19-L43
To summarize:
previous account information and keys (signer, predecessor and signer_public_key)
gas information
all promise methods, cause they involve other contracts

How to unit test graphql query/mutation error with Mocha and Chai?

Since graphql error is not an standard Error. It's a GraphQLError
I can't figure out how to write unit test when graphql query/mutation throw an exception.
Here is my try:
it('should throw an error when lack of "id" argument for user query', async () => {
const body = {
query: `
query user{
user {
id
name
}
}
`
};
try {
const actualValue = await rp(body);
} catch (err) {
logger.error(err);
}
// logger.info(actualValue);
expect(1).to.be.equal(1);
// expect(actualValue).to.throw()
});
I found some tests in graphql.js repo. https://github.com/graphql/graphql-js/blob/master/src/tests/starWarsQuery-test.js#L393
But I think the way they test the query/mutation error is not correct.
They just do a deep equal with the error. But before running the test suites, how do I know the error data structure like locations: [{ line: 5, column: 13 }],? Maybe I should use snapshot testing so that I don't need to know the error data structure?
Check this package https://github.com/EasyGraphQL/easygraphql-tester there is an example with mocha and chai on the documentation

Resources