# Terminate Gateway Async Thread

**URL:** <https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638>\
**Category:** Ignition\
**Tags:** ignition79\
**Created:** [December 1, 2021, 6:18pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638 "2021-12-01T18:18:47Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 1, 2021, 6:18pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/1 "2021-12-01T18:18:47Z")

</div>

Is there a way to terminate/force close an async thread created from a tag event?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [December 1, 2021, 6:22pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/2 "2021-12-01T18:22:59Z")

</div>

No, you just need to be careful not to hang yourself. If you spawned off an async infinite loop you need to restart your gateway now.

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 1, 2021, 6:34pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/3 "2021-12-01T18:34:08Z")

</div>

No, I have a java file watching service in the thread. I have a getStatus() function that returns the thread Id, if it is alive, and if it is interrupted. Sometimes it stops working despite it still being alive and not interrupted.

while trying to get it to work, I spawned a second thread by accident.

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 1, 2021, 6:44pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/4 "2021-12-01T18:44:45Z")

</div>

Looks like I will have to interrupt() the thread then join() it with the other thread to get rid of it without a gateway start.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 1, 2021, 6:47pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/5 "2021-12-01T18:47:21Z")

</div>

That kind of async thread should be checking a memory tag as part of its otherwise infinite loop. .interrupt() response is somewhat voluntary–only checked by java for you on certain operations.

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 1, 2021, 7:02pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/6 "2021-12-01T19:02:23Z")

</div>

In my async while loop I check it every iteration using the `isInterrupted()` method.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 1, 2021, 7:05pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/7 "2021-12-01T19:05:08Z")

</div>

Do the other operations in the loop have timeouts to ensure .isInterrupted() is checked reliably?

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 1, 2021, 7:21pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/8 "2021-12-01T19:21:06Z")

</div>

```auto
while self.thread.isAlive() and not self.thread.isInterrupted():				
	k = self.watcher.poll(5,TimeUnit.SECONDS)
	if k:
		for e in k.pollEvents():
			kind = e.kind()
			
			if kind == swek.ENTRY_DELETE:
				filePath = p.resolve(e.context()).toString()
				system.tag.write('Cutting/watchService/deletedFile',filePath)
					
			elif kind == swek.ENTRY_CREATE or kind == swek.ENTRY_MODIFY:
				filePath = p.resolve(e.context()).toString()
				system.tag.write('Cutting/watchService/changedFile',filePath)
		k.reset()

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 1, 2021, 7:56pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/9 "2021-12-01T19:56:41Z")

</div>

Not sure what the problem is. But two recommendations:

- Don’t bother checking for alive within the thread–it will never be false.
- Consider using the static method `Thread.interrupted()` instead of the instance method.

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 2, 2021, 3:14pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/10 "2021-12-02T15:14:03Z")

</div>

I think my problem is coming from the fact that the directory I’m watching is a mapped drive. I think I read that the `WatchService API` is not suited for this and I should use `FileAlterationMonitor` instead.

I’ve started to port a Java example over to Jython, but I’m getting tripped up at the `@overide` parts as I don’t understand how to register the file events.

What I have so far

```auto
from java.io import File
#from org.apache.commons.io import FileDeleteStrategy,FileUtils
from org.apache.commons.io.filefilter import FileFilterUtils
from org.apache.commons.io.monitor import FileAlterationListenerAdaptor
from org.apache.commons.io.monitor import FileAlterationMonitor
from org.apache.commons.io.monitor import FileAlterationObserver

class FileMonitor():
	isRunning = False

	def __init__ (self):
		self.monitor = None
		self.thread = None
		self.run()
		
	def _doAsync(self):
		self.isRunning = True
		
		# Directory to monitor for changes
		directory = File("L:\Files\CFC MINIPLOTS").toPath()
		# Only monitor directory for changes on pdf file extensions
		fileFilter = FileFilterUtils.suffixFileFilter("pdf")
		# Create a new file alteration observer
		observer = FileAlterationObserver(directory, fileFilter)	
		# Add listner to the observer	
		observer.addListner(FileAlterationListenerAdaptor())
		# Create file alteration monitor at 1 second polling rate
		self.monitor = fileAlterationMonitor(1000,observer)
		# Start monitoring for file alterations
		self.monitor.start()
		
		logger = system.util.getLogger("File Alteration Monitoring")
		
		while self.isRunning and not self.thread.interrupted():
			logger.debug('In While Loop')
			
	def run(self): # Create and run the File Monitor in an Aysnc Thread
		self.thread = system.util.invokeAsynchronous(self._doAsync)
			
	def stop(self):
		self.isRunning = False
		self.monitor.stop()

		
'''	
Tutorials Point Java Example Code

   	usingFileAlterationMonitor() throws IOException {

      FileAlterationObserver observer = new
      FileAlterationObserver(parentDirectory);
      observer.addListener(new FileAlterationListenerAdaptor(){
         @Override
         public void onDirectoryCreate(File file) {
            System.out.println("Folder created: " + file.getName());
         }
         @Override
         public void onDirectoryDelete(File file) {
            System.out.println("Folder deleted: " + file.getName());
         }
         @Override
         public void onFileCreate(File file) {
            System.out.println("File created: " + file.getName());
         }
         @Override
         public void onFileDelete(File file) {
            System.out.println("File deleted: " + file.getName());
         }
      });
      //create a monitor to check changes after every 500 ms
      FileAlterationMonitor monitor = new FileAlterationMonitor(500, observer);
      try {
         monitor.start();
         //create a new directory
         File newFolder = new File("test");
         File newFile = new File("test1");
         newFolder.mkdirs();
         Thread.sleep(1000);
         newFile.createNewFile();
         Thread.sleep(1000);
         FileDeleteStrategy.NORMAL.delete(newFolder);
         Thread.sleep(1000);
         FileDeleteStrategy.NORMAL.delete(newFile);
         Thread.sleep(1000);
         monitor.stop(10000);
      } catch(IOException e) {
         System.out.println(e.getMessage());
      } catch(InterruptedException e) {
         System.out.println(e.getMessage());
      } catch (Exception e) {
         System.out.println(e.getMessage());
      }
   }
}

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [December 2, 2021, 4:25pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/11 "2021-12-02T16:25:32Z")

</div>

To subclass a Java class in Jython, you make a new class that’s a subclass of the Java one, call the Java constructor (if necessary) by defining an ` __init__ ` method that takes the same parameters and calls `super. __init__ `, then override the Java methods by defining a method with the same arity plus the `self` argument:

```python
class NetworkListenerAdapter(FileAlterationListenerAdaptor):
    def __init__ (self):
        # do any initialization; superclass has no parameters
        pass

    def onDirectoryCreate(self, file):
        pass
        
    def onDirectoryDelete(self, file):
        pass

```

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 2, 2021, 4:33pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/12 "2021-12-02T16:33:46Z")

</div>

I made some changes and was on this track, but I didn’t quite have it correct. Thanks for the example, makes more sense now.

```auto
from java.io import File
#from org.apache.commons.io import FileDeleteStrategy,FileUtils
from org.apache.commons.io.filefilter import FileFilterUtils
from org.apache.commons.io.monitor import FileAlterationListenerAdaptor
from org.apache.commons.io.monitor import FileAlterationMonitor
from org.apache.commons.io.monitor import FileAlterationObserver

class FileMonitor():
	isRunning = False

	def __init__ (self):
		self.monitor = None
		self.thread = None
		self.run()
		
	def _doAsync(self):
		self.isRunning = True
		
		# Directory to monitor for changes
		directory = File("L:\Files\CFC MINIPLOTS").toPath()
		# Only monitor directory for changes on pdf file extensions
		fileFilter = FileFilterUtils.suffixFileFilter(".pdf")
		# Create a new file alteration observer
		observer = FileAlterationObserver(directory, fileFilter)	
		# Add listner to the observer with overridden class methods	
		observer.addListner(NetworkListenerAdapter())
		# Create file alteration monitor at 1 second polling rate
		self.monitor = fileAlterationMonitor(1000,observer)
		# Start monitoring for file alterations
		self.monitor.start()
		
		logger = system.util.getLogger("File Alteration Monitoring")
		logger.debug('Thread Started')
			
	def run(self): # Create and run the File Monitor in an Aysnc Thread
		self.thread = system.util.invokeAsynchronous(self._doAsync)
			
	def stop(self):
		self.isRunning = False
		self.monitor.stop()

class NetworkListenerAdapter(FileAlterationListenerAdaptor):
	def __init__ (self):
		self.logger = system.util.getLogger("File Alteration Monitoring")
		
	def onFileChange(self, file):
		self.logger.debug('File Change Detected')
		system.tag.write('Cutting/watchService/changedFile',filePath)
		
	def onFileCreate(self, file):
		self.logger.debug('File Creation Detected')
		system.tag.write('Cutting/watchService/changedFile',filePath)
		
	def onfileDelete(self, file):
		self.logger.debug('File Deletion Detected')
		system.tag.write('Cutting/watchService/deletedFile',filePath)

```

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 2, 2021, 6:55pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/13 "2021-12-02T18:55:55Z")

</div>

Okay, I’ve debugged some typos in my script. Now, when I start the file monitor, the thread state is `Runnable` but I don’t see any file events being logged. Any idea what I’m missing?

```auto
from java.io import File
#from org.apache.commons.io import FileDeleteStrategy,FileUtils
from org.apache.commons.io.filefilter import FileFilterUtils
from org.apache.commons.io.monitor import FileAlterationListenerAdaptor
from org.apache.commons.io.monitor import FileAlterationMonitor
from org.apache.commons.io.monitor import FileAlterationObserver
from java.lang import Exception

class FileMonitor():
	isRunning = False

	def __init__ (self):
		self.monitor = None
		self.thread = None
		self.run()
		
	def _doAsync(self):
		self.isRunning = True
		logger = system.util.getLogger("File Alteration Monitoring")
		# Directory to monitor for changes
		directory = str(File("C:\Users\dhayes\Desktop\TestFolder").toPath())
		# Only monitor directory for changes on pdf file extensions
		fileFilter = FileFilterUtils.suffixFileFilter(".pdf")
		# Create a new file alteration observer
		observer = FileAlterationObserver(directory, fileFilter)	
		# Add listner to the observer with overridden class methods	
		observer = observer.addListener(NetworkListenerAdapter())
		# Create file alteration monitor at 1 second polling rate
		self.monitor = FileAlterationMonitor(1000,observer)
		# Start monitoring for file alterations
		self.monitor.start()
		logger.debug('Thread Started')
		print 'Thread Started'
						
	def run(self): # Create and run the File Monitor in an Aysnc Thread
		self.thread = system.util.invokeAsynchronous(self._doAsync)
			
	def stop(self):
		self.isRunning = False
		self.monitor.stop()

class NetworkListenerAdapter(FileAlterationListenerAdaptor):
	def __init__ (self):
		self.logger = system.util.getLogger("File Alteration Monitoring")
		
	def onFileChange(self, file):
		self.logger.debug('File Change Detected')
		system.tag.write('Cutting/watchService/changedFile',filePath)
		
	def onFileCreate(self, file):
		self.logger.debug('File Creation Detected')
		system.tag.write('Cutting/watchService/changedFile',filePath)
		
	def onfileDelete(self, file):
		self.logger.debug('File Deletion Detected')
		system.tag.write('Cutting/watchService/deletedFile',filePath)

```

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 2, 2021, 7:31pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/14 "2021-12-02T19:31:44Z")

</div>

Here’s my problem, not sure what this means…

```auto
14:30:41.868 [AWT-EventQueue-0] INFO designer.update-and-save - Save finished in 40ms.
<type 'org.apache.commons.io.monitor.FileAlterationObserver'>
14:30:55.773 [AWT-EventQueue-0] ERROR com.inductiveautomation.ignition.client.util.gui.ErrorUtil - <HTML>Error running function from <code>fpmi.system.invokeAsynchronous</code>
com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last):
  File "<module:shared.fileMonitor>", line 32, in _doAsync
TypeError: org.apache.commons.io.monitor.FileAlterationMonitor(): 2nd arg can't be coerced to org.apache.commons.io.monitor.FileAlterationObserver[]

```

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 2, 2021, 7:47pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/15 "2021-12-02T19:47:16Z")

</div>

Looks like you need to supply a list/array of observers.

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 2, 2021, 7:48pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/16 "2021-12-02T19:48:08Z")

</div>

I just figured it out. I had to do this before passing the observer to the FAM

```auto
observer.initialize()

```

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 3, 2021, 1:59pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/18 "2021-12-03T13:59:02Z")

</div>

So I have the file monitor working, but in order to keep the thread `Runnable`, I had to add this while loop

```auto
while self.isRunning and not self.thread.interrupted():
    observer.checkAndNotify()

```

This is not good, as you would put it, “This is a horrible CPU burning script.” It runs at 24% CPU by itself lol. I can’t get the file events to register unless I manually call the `checkAndNotify()` method. Is there a way to make the check `poll()` instead of loop out of control?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [December 3, 2021, 2:08pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/19 "2021-12-03T14:08:52Z")

</div>

Why do you want it “Runnable”? That explicitly means it will burn CPU. Waiting is the correct state when literally waiting on a notification.

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 3, 2021, 2:12pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/20 "2021-12-03T14:12:05Z")

</div>

It is `Runnable` by default? That is its state when I call it, not sure how to make it `Timed_Waiting`. You think it would be that since `FileAlterationMonitor` is being feed a 1000 ms poll rate. However, if I don’t have a while loop, the thread goes immediately into a `Terminated` state.

Weird thing is the Monitor has two methods `run()` and `start()`. Maybe I should call `run()` then `start()` instead of just `start()`?

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [December 3, 2021, 2:16pm UTC](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638/21 "2021-12-03T14:16:23Z")

</div>

Interesting…

```auto
run
public void run()
Runs this monitor.
Specified by:
run in interface Runnable

```

[Next page](https://forum.inductiveautomation.com/t/terminate-gateway-async-thread/53638.md?page=2)
