star-micronics / react-native-star-io10

react-native-star-io10 is a library for supporting application development for Star Micronics devices.
Other
88 stars 54 forks source link

The device is in use by another process #12

Closed mic7010 closed 3 months ago

mic7010 commented 3 years ago

I am seeing this error on occasion. Restarting the app resolves is. Is there a way I can check for this and/or kill the process in use?

bandit-ibayashi commented 3 years ago

@mic7010 I think the problem is not caused by this project, but by the environment. Would this problem occur only with this react-native-star-io10?

mic7010 commented 3 years ago

This error message is returned from your SDK. Under what circumstances does it occur? Is there something I can do to recover?

bandit-ibayashi commented 3 years ago

Unfortunately, I have not seen this error on my side. Could you provide us with information about your environment and screenshots of the errors you encounter?

Brendan-csel commented 3 years ago

I've had this too - but so far only intermittently when debugging and react-native hot reloads - possibly without closing the printer. Closing and restarting the app seems to resolve the issue.

bandit-ibayashi commented 2 years ago

As mentioned the issue #25, we have updated the SDK as version 1.1.0. If you continue to have this issue after updating, please let us know.

kickbk commented 2 years ago

Still happening.

export default async function findStarPrinters(
  setStarPrinters: (starPrinters: StarPrinter[]) => void
) {
  let printers: StarPrinter[] = [];

  const interfaceTypes = [
    InterfaceType.Lan,
    InterfaceType.Bluetooth,
    InterfaceType.BluetoothLE,
    InterfaceType.Usb,
  ];
  let interfacesDiscovered = 0;
  // Iterate through the interfaces. If we discover all at the same time, it may break if bluetooth is missing/not permitted, and it will never try to discover USB.
  interfaceTypes.map(async (interfaceType) => {
    try {
      const manager = await StarDeviceDiscoveryManagerFactory.create([
        interfaceType,
      ]);

      // manager.discoveryTime = 10000; // WARNING: When we activate this, it stops onPrinterFound from opening and listening to the printer found.

      manager.onPrinterFound = (printer: StarPrinter) => {
        console.log("FOUND A PRINTER", printer.information?.model);
        printer.printerDelegate.onCoverOpened = () => {
          console.log("Cover open");
        };
        printer.printerDelegate.onCoverClosed = () => {
          console.log("cover closed");
        };
        printer.open(); <<< On app reload (not restart) this will return an error, see error below.
      };

      manager.onDiscoveryFinished = () => {
      };

      await manager.startDiscovery();
    } catch (error) {
      console.log(interfaceType, error);
    }
  });
}

The error:

[Unhandled promise rejection: StarIO10InUseError: The device is in use by another process.]
at http://192.168.1.101:8081/index.bundle?platform=ios&dev=true&hot=false&minify=false:456075:321 in _createSuperInternal
at http://192.168.1.101:8081/index.bundle?platform=ios&dev=true&hot=false&minify=false:456089:25 in StarIO10Error
at http://192.168.1.101:8081/index.bundle?platform=ios&dev=true&hot=false&minify=false:456261:321 in _createSuperInternal
at http://192.168.1.101:8081/index.bundle?platform=ios&dev=true&hot=false&minify=false:456272:25 in StarIO10InUseError
at http://192.168.1.101:8081/index.bundle?platform=ios&dev=true&hot=false&minify=false:455955:66 in _buildObject$
at http://192.168.1.101:8081/index.bundle?platform=ios&dev=true&hot=false&minify=false:455930:41 in _buildObject
at http://192.168.1.101:8081/index.bundle?platform=ios&dev=true&hot=false&minify=false:455896:83 in create$

If you want to listen to the printer constantly so as to get status change notifications, then you cannot .close() it. Then when reloading the app, the printer would never be closed. Restarting the app will obviously be different since the printer instance is destroyed. It would make sense that the open() method would check for running instances before instantiating a new one. Also have a look at my notes regarding possible missing interfaces and how discovery will break for other interfaces if one is missing.

gare-bear commented 2 years ago

@kickbk What you're seeing is the expected behavior. In order for events like offline, paper out, cover open/closed to trigger, you need to have an active connection to the printer. If you hot-reload, then the connection to the printer will not be closed, and thus you get this error. Under normal circumstances, this shouldn't happen.

Another thing to consider is if you have app running on several different devices, you could run into this problem. The printer can only handle one connection at a time, so subsequent calls to printer.open() will fail with the above error.

Depending on your use case, you should consider opening/closing the port on each print.

naotoisoda commented 2 years ago

I'm seeing the same error message.

The device is in use by another process.

In my case , this error occurs when the program orders the star-io10SDK to print a receipt in a row. So, this error probably occurs because the SDK is ordered to print another receipt while printing a receipt.

Is there some way to check whether the printer is busy or not ?

shibatanien commented 1 year ago

What if I suggest leveraging this error message as considering the printer is being busy.

The device is in used by another process

If I try request to print multiple things back to back, the very first request prints without issue but the consecutive requests fail because the first print request is not considered done yet (not closed and disposed). In other words, if I request to print something before the ongoing print function closes connection and disposes the printer object, it throws this error. Being the error as a clue of wether the printer is busy or not, I could make the request once again if this specific error it thrown, recursively.

Another important thing to take note is that, as @gare-bear mentioned, a printer can only handle one connection at a time. I tested this in action and found out that, if a different device tries to open a connection to a printer that has already been opened by another device, it will throw a similar error that goes:

The device is in used by another host

Therefore, it is critical to always open, close, and dispose using try catch finally statements at every print request instead of leaving the connection open. Unless the app is hot-reloaded during the print function is being executed, the printer object will not be kept opened in this way.

With these in mind, one of the solutions I figured is to recursively invoke print function if printing fails, but for a limited number of times.

This is what I wrote to cope with printer busyness (in JavaScript):

export async function PrintItemOrder(item_order, retried_count=0) {
    let settings = new StarConnectionSettings()
    settings.interfaceType = InterfaceType.Lan
    settings.identifier = "00-00-00-00-00-00"
    const printer = new StarPrinter(settings)
    printer.openTimeout = 2000
    try {
        const printer_builder = new StarXpandCommand.PrinterBuilder()

        printer_builder
        .styleInternationalCharacter(StarXpandCommand.Printer.InternationalCharacterType.Usa)
        .styleCharacterSpace(0)
        .add(
            new StarXpandCommand.PrinterBuilder()
                .styleMagnification(new StarXpandCommand.MagnificationParameter(2, 2))
                .actionPrintText("NEW ORDER\n")
        )
        .actionPrintText("${item_order.name}\n")
        .actionFeedLine(1)
        .actionCut(StarXpandCommand.Printer.CutType.Partial)

        var builder = new StarXpandCommand.StarXpandCommandBuilder();
        builder.addDocument(
            new StarXpandCommand.DocumentBuilder()
            .addPrinter(printer_builder)
        );

        let commands = await builder.getCommands();
        await printer.open()
        await printer.print(commands);

    } catch(error) {
        // optional: wait 5 seconds until recurse
        await new Promise(resolve => setTimeout(resolve, 5000))

        // if retry count reaches 5, give up. It would be nice to save this info to DB to let staff know a certain item failed to print
        if(retried_count === 5) {
            return
        }

        // recurse the function by adding the same function to the call stack but with incremented retried_count.
        // The error could be related to the printer being used by another process or host, or even device on being found
        PrintItemOrder(item_order, retried_count=retried_count+1)
    } finally {
        // no matter the outcome of printing, close and dispose the printer object
        await printer.close()
        await printer.dispose()
    }

And in my specific case, I would like to print each item into separate paper. This requires looping over a list of items to be printed back to back. However, assuming that I utilise the print function written above, simply looping the list of items using for or map can immediately lead to first item being printed successfully and subsequent orders throwing error and unnecessarily recursing the function until it succeeds to print. To get around this, I found using for of loop combined with async await could solve this specific problem:

async function printItemOrders(item_orders) {
    for(const item of item_orders) {
        await PrintItemOrder(item)
     }
 }
steelzeh commented 5 months ago

There should be a way close the open connections even if the instance is gone. There are use cases where having the printer connection open is required like reading barcodes or monitoring the printer connection.

once .close() has been called, no more updates arrive from the printer, so closing the printer connection is not an option.

I agree that this might be an edge case but it would be nice like @kickbk suggest that .open() would either reuse the existing connection or close it and open a new one, if the connection is made from the same device to the same printer.

Or let us handle it ourselves so that if we get StarIO10InUseError we can manually close the connection and open a new one. But once the app has been reloaded the instance is lost, and there is no way to close it without restarting the app

@bandit-ibayashi @gare-bear

can-miki commented 3 months ago

Hello everyone,

We would like to express our gratitude for your cooperation and support with the issues. We take your feedback very seriously as it plays an important role in improving our products and services.

Your active feedback and support are indispensable in building a better community. We sincerely appreciate your time and consideration.

Best regards.