Errors prevented startup: While running post-startup callbacks: error: write EPIPE after importing file to methods.js

I need to call an async function that resides in a path (namely imports/ui/pages/plan-selection.js)
from a server method, that resides in a different path,( namely imports\api\exports\methods.js)
so I exported the async function as a variable such as:

module.exports.search_for_products=search_for_products;

and then imported it into the methods.js file:

import {search_for_products } from ‘…/…/ui/pages/plan-selection.js’;

to further have access to it and use wrapAsync/await to get the result the callback of the function gives.
The thing is when I include this line:

import {search_for_products } from ‘…/…/ui/pages/plan-selection.js’;

I start getting the below error:

To notice here that in the file plan-selection.js there is a line

import ‘./plan-selection.html’;

I tried including the plan-selection.html or plan-selection.js in some directory files such as server/index.js but did not have any results, do you have any suggestions why this happens and what should I do?

I’m guessing that plan-selection.html is a blaze template?

Blaze (vanilla) does not support server side rendering and template aren’t available on the server.

Easiest solution is to refactor the function into a separate file without the blaze dependency which both server and client can import.

Alternatively, I believe some folks managed to get blaze-ssr working, which implies that the templates would exist on the server, allowing you to keep the files the same. But I expect that you will run into other issues

1 Like

yes, you are right @coagmano plan-selection.html is a blaze template and the plan-selection.js contains the corresponding template logic as well as the async function I would like to use in server side method.
I will follow your advice and come back to follow up with my progress. Thanks a lot!
From what I read so far the right directory/file to include my function would be in the methods.js file and convert it to Meteor Method instead of just function (as it is now) since it should be called from client and server side as well, what is your opinion?

i would extract only the function and import it where you need.

you can make a /utils/ folder or /libs folder. Basically, business logic should be as free from framework code as possible. Personally i also started to introduce folders named /business where i have plain functions like this.

1 Like

@macrozone thanks for the advice! but shouldn’t I convert it into a Meteor method function though?
I believe yes, since it will be called from both sides server and client…

It depends on the function. It only needs to be a method when you want the client to communicate with the server.
If not, a plain function is fine

thank you so far for your answers!Helped me to figure out some meteor things I had messed.
Following your advice I have saved my plain function search_for_products under a directory such as lib/search_for_products .js in order to be accessible from both client or server side.
I have written my async function search_for_products .js using callback style

const search_for_products  = (params,callback )=> { 
...
callback(result)
}

instead of (error, result) style. Is it wrong given that I want to call it using wrapAsync from the meteor server side method like following:

var future = new Future();
const convertAsynctoSync = Meteor.wrapAsync(search_for_products  );
const resultofAsynctoSync=convertAsynctoSync(params)//passing functions params
return resultofAsynctoSync;

it seems as I am missing something here with Promises etc but could not figure it out
in the console I can see that when that method is called from main.js it returns undefined in result although from logs it seems as it is invoked.
Any suggestions
thank you

I think you’re perhaps misunderstanding some of the core concepts of Meteor and its use of Fibers for sync-style programming.

It may be helpful to just go over some of the fundamentals.

On the server, Meteor code uses Fibers to achieve sync-style programming, in which callbacks are not used. However, Fibers are an example of coroutines, and have nothing to do do with Promises and async/await syntax. Meteor normally hides the underlying Fiber code for you, which makes it really easy to get started.

Meteor.wrapAsync ensures that a function having a callback with a signature of (error, result) runs within a Fiber. However, await is a Promise-based syntax and you cannot use await to get the result of a Fiber.

In Meteor, it’s fine to mix Fibers with Promises (and async/await), but it’s important to remember that they are completely different things and you should be aware of how they can be used together.

Consider an aynchronous function getData, which has a callback with an (error, result) signature. We can get the result in 4 ways (I’ve ignored error handling for simplicity):

// Get the result in the callback (traditional JavaScript)
getData((error, result) => {
  console.log(result); // result is available here
});
// result is undefined (NOT available here)
// Use Meteor's Fibers (traditional Meteor)
const getDataWrapped = Meteor.wrapAsync(getData);
const result = getDataWrapped();
console.log(result);
// Use Promises
const getDataPromise = () => {
  return new Promise(resolve => {
    getData((error, result) => {
      resolve(result);
    });
  });
}
getDataPromise()
  .then(result => {
    console.log(result); // Result is available here
)};
// Result is undefined (NOT available here)
// Using async/await
const getDataPromise = () => {
  return new Promise(resolve => {
    getData((error, result) => {
      resolve(result);
    });
  });
}
const result = await getDataPromise();

You will notice that Meteor’s Fibers and async/await both result in sync-style programming, where the result is available “inline”.

However, there is a gotcha with async/await. You must wrap your sync-style await code in an async function. Results and “inlining” are only available inside that function.

Finally, on the client, there are no Fibers. You must use callbacks, or wrap callbacks in Promises to use async/await.

Take a look at these articles, where I go into a bit more depth:

1 Like

thank you for the answers and the useful posts.
After some tries I was able to get the result with the below code:

  	let promise=new Promise((resolve, reject)=>{
  	search_for_products(options,weight_1,weight_2,weight_3,weight_4,(Products) =>{
  	
  		resolve(Products);
  	})

  	})
  	let result=await promise
  	console.log("resolve result",result)
  	return result