# system.net.httpClient() with TIME\_WAIT due to pooling?

**URL:** <https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203>\
**Category:** Ignition\
**Created:** [July 31, 2025, 2:15pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203 "2025-07-31T14:15:17Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![framebuilder](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@framebuilder](https://forum.inductiveautomation.com/u/framebuilder)\
**Post date:** [July 31, 2025, 2:15pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/1 "2025-07-31T14:15:17Z")

</div>

We are using system.net.httpClient() with PUT to call some Microsoft REST APIs. It gets triggered every few seconds.with system.util.invokeAsynchronous() and appears to work fine. We have logging setup and anything not returning a 200 gets logged (1-2 per week). But it seems like a lot of TCP ports are being left open in TIME\_WAIT state (Windows OS).

I think I remember hearing system.net.httpClient() has connection pooling and other things going on behind the scenes so maybe it's trying to re-use some open ports instead of having to re-do the entire connection each time. The high port number connections appear to be cycling and closing but there are always about 100-200 of them open at any one time. Can anyone confirm this is the case and if so, are there any pooling configurations we can make?

---

<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:** [July 31, 2025, 2:20pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/2 "2025-07-31T14:20:50Z")

</div>

Are you creating a new httpClient object for every request? If so, stop doing that. Use a project library script outer level object to hold a single one and use it everywhere.

---

<div class="post-metadata">

**Author:** ![Cody\_Morgan](https://avatars.discourse-cdn.com/v4/letter/c/db5fbb/32.png) [@Cody\_Morgan](https://forum.inductiveautomation.com/u/Cody_Morgan)\
**Post date:** [July 31, 2025, 2:21pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/3 "2025-07-31T14:21:18Z")

</div>

Are you reusing the client object returned by `system.net.httpClient()` or creating a new one each time? If creating a new one each time, try reusing the object instead.

EDIT: Phil beat me to it

---

<div class="post-metadata">

**Author:** ![framebuilder](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@framebuilder](https://forum.inductiveautomation.com/u/framebuilder)\
**Post date:** [August 1, 2025, 8:15pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/4 "2025-08-01T20:15:21Z")

</div>

I'm sorry but I don't understand exactly what that means.  
We have a Gateway Event Script tag change script that executes system.util.invokeAsynchronous() with a function from the Project Library that includes the PUT with system.net.httpClient()

---

<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:** [August 1, 2025, 8:18pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/5 "2025-08-01T20:18:14Z")

</div>

Don't:

```python
def someAsyncFunction():
	client = system.net.httpClient()
	client.doSomething()

```

Do:

```python
client = system.net.httpClient()

def someAsyncFunction():
	client.doSomething()

```

(With all of this in the project library).

---

<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:** [August 1, 2025, 8:18pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/6 "2025-08-01T20:18:45Z")

</div>

> [@framebuilder](#):
>
> function from the Project Library

Is that function calling `system.net.httpClient()` every time. If so, don't. Put

```python
someClient = system.net.httpClient()

```

in that library script **outside** any function `def`. That will make **one** httpClient instance and hold it in between project edits. Use `someClient` in the function wherever you are current calling `system.net.httpClient()`.

Edit: Paul was faster.

---

<div class="post-metadata">

**Author:** ![framebuilder](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@framebuilder](https://forum.inductiveautomation.com/u/framebuilder)\
**Post date:** [August 1, 2025, 8:35pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/7 "2025-08-01T20:35:43Z")

</div>

Yep, you guys called it. We're using someClient = system.net.httpClient() inside of the def. We'll move it. Thanks for the explanation.

---

<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:** [August 1, 2025, 8:43pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/8 "2025-08-01T20:43:40Z")

</div>

As a note, in 8.3, if you're solely using `system.net.httpClient()` (all defaults), you'll be able to substitute calls directly for an automatic instance.  
That is:

# 8.1

```python
client = system.net.httpClient()
client.get(someUrl)

```

Can become:

# 8.3

```python
system.net.httpClient.get(someUrl)

```

So you don't need to define (potentially multiple) default `system.net.httpClient` instances in all your project library scripts.

---

<div class="post-metadata">

**Author:** ![ricardo.ortolani](https://avatars.discourse-cdn.com/v4/letter/r/c68b51/32.png) [@ricardo.ortolani](https://forum.inductiveautomation.com/u/ricardo.ortolani)\
**Post date:** [August 4, 2025, 1:18pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/9 "2025-08-04T13:18:33Z")

</div>

Hello @paul-griffith and @pturmel

I have another quick question, in the gateway event scripts, under Tag Change I am using the following call:

```python
system.util.invokeAsynchronous(GATEWAY_FUNCTION.FunctionName, [var1, var2, var3])

```

Would you recommend running the "invokeAsynchronous" in the Tag Change script, or move to the Project Library?

---

<div class="post-metadata">

**Author:** ![ryan.white](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/ryan.white/32/73193_2.png) [@ryan.white](https://forum.inductiveautomation.com/u/ryan.white)\
**Post date:** [August 4, 2025, 3:22pm UTC](https://forum.inductiveautomation.com/t/system-net-httpclient-with-time-wait-due-to-pooling/109203/10 "2025-08-04T15:22:04Z")

</div>

If its in a gateway event script, don't even use the `invokeAsynchronous` call, its already in its own thread pool. If you need a dedicated thread for it, select the dedicated thread option when configuring the event.

> **[Gateway Event Scripts | Ignition User Manual](https://www.docs.inductiveautomation.com/docs/8.1/platform/scripting/scripting-in-ignition/gateway-event-scripts#timer-script-settings)**
>
> Gateway Event Scripts Overview
