On Windows, netbird-ui.exe should only run one application instance #439

Open
opened 2025-11-20 05:11:21 -05:00 by saavagebueno · 3 comments
Owner

Originally created by @rgl on GitHub (Sep 6, 2023).

Describe the problem
On Windows, netbird-ui.exe should only run one application instance.

To Reproduce
Steps to reproduce the behavior:

  1. Execute netbird-ui.exe.
  2. Execute netbird-ui.exe again.
  3. Notice that two Netbird icons appear in the Windows systray.

Expected behavior
It should only show a single icon in the Windows systray.

Screenshots
image

Originally created by @rgl on GitHub (Sep 6, 2023). **Describe the problem** On Windows, netbird-ui.exe should only run one application instance. **To Reproduce** Steps to reproduce the behavior: 1. Execute `netbird-ui.exe`. 2. Execute `netbird-ui.exe` again. 3. Notice that two Netbird icons appear in the Windows systray. **Expected behavior** It should only show a single icon in the Windows systray. **Screenshots** ![image](https://github.com/netbirdio/netbird/assets/43356/44cf7fe7-3773-46e0-8b8d-dde0e041b31c)
saavagebueno added the bugclientclient-uitriage-needed labels 2025-11-20 05:11:21 -05:00
Author
Owner

@mlsmaycon commented on GitHub (Sep 6, 2023):

You ran the regular upgrade with the installer?

@mlsmaycon commented on GitHub (Sep 6, 2023): You ran the regular upgrade with the installer?
Author
Owner

@rgl commented on GitHub (Sep 7, 2023):

@mlsmaycon, I've used netbird_installer_0.23.0_windows_amd64.exe /S (you can see the full script that installs it at https://github.com/rgl/my-windows-ansible-playbooks/blob/main/roles/netbird/files/install-netbird.ps1).

@rgl commented on GitHub (Sep 7, 2023): @mlsmaycon, I've used `netbird_installer_0.23.0_windows_amd64.exe /S` (you can see the full script that installs it at https://github.com/rgl/my-windows-ansible-playbooks/blob/main/roles/netbird/files/install-netbird.ps1).
Author
Owner

@mfuller-vso commented on GitHub (Jan 23, 2024):

I ran into this issue as well on windows 10. After adding in some debug logging when it got to process.Signal(syscall.Signal(0)) it output signal: not supported by windows.

Looking at this post https://stackoverflow.com/questions/15204162/check-if-a-process-exists-in-go-way I was able to make the process not start multiple instances on windows by modifying checkPIDFile to the following. There are likely better methods of doing this, but it is outside of my skill-set to properly implement.

I also tested on ubuntu 20.04 by backgrounding the process and attempting to start it several times, which resulted in it correctly not starting another instance of the executable instead returning the error from the section where syscall is executed.

This might be one way to go about it minimal change, just going to leave this here as food for thought.

// checkPIDFile exists and return error, or write new.
func checkPIDFile() error {
	pidFile := path.Join(os.TempDir(), "wiretrustee-ui.pid")
	if piddata, err := os.ReadFile(pidFile); err == nil {
		if pid, err := strconv.Atoi(string(piddata)); err == nil {
			if process, err := os.FindProcess(pid); err == nil {
				if runtime.GOOS == "windows" {
					return fmt.Errorf("process already exists: %d", pid)
				} else if err := process.Signal(syscall.Signal(0)); err == nil {
					return fmt.Errorf("process already exists: %d", pid)
				}
			}
		}
	}

	return os.WriteFile(pidFile, []byte(fmt.Sprintf("%d", os.Getpid())), 0o664) //nolint:gosec
}
@mfuller-vso commented on GitHub (Jan 23, 2024): I ran into this issue as well on windows 10. After adding in some debug logging when it got to `process.Signal(syscall.Signal(0))` it output `signal: not supported by windows`. Looking at this post https://stackoverflow.com/questions/15204162/check-if-a-process-exists-in-go-way I was able to make the process not start multiple instances on windows by modifying checkPIDFile to the following. There are likely better methods of doing this, but it is outside of my skill-set to properly implement. I also tested on ubuntu 20.04 by backgrounding the process and attempting to start it several times, which resulted in it correctly not starting another instance of the executable instead returning the error from the section where syscall is executed. This might be one way to go about it minimal change, just going to leave this here as food for thought. ```go // checkPIDFile exists and return error, or write new. func checkPIDFile() error { pidFile := path.Join(os.TempDir(), "wiretrustee-ui.pid") if piddata, err := os.ReadFile(pidFile); err == nil { if pid, err := strconv.Atoi(string(piddata)); err == nil { if process, err := os.FindProcess(pid); err == nil { if runtime.GOOS == "windows" { return fmt.Errorf("process already exists: %d", pid) } else if err := process.Signal(syscall.Signal(0)); err == nil { return fmt.Errorf("process already exists: %d", pid) } } } } return os.WriteFile(pidFile, []byte(fmt.Sprintf("%d", os.Getpid())), 0o664) //nolint:gosec } ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: SVI/netbird#439