@@ -47,6 +47,9 @@ abstract class AbstractGitpodPortForwardingService : GitpodPortForwardingService
4747 // Last observed ports list, used to prevent duplicate processing
4848 private var lastPortsList = listOf<PortsStatus >()
4949
50+ // Debounce job for port updates
51+ private var debounceJob: Job ? = null
52+
5053 init { start() }
5154
5255 private fun start () {
@@ -98,15 +101,24 @@ abstract class AbstractGitpodPortForwardingService : GitpodPortForwardingService
98101 }
99102
100103 override fun onNext (response : Status .PortsStatusResponse ) {
101- application.invokeLater {
102- if (syncInProgress.compareAndSet(false , true )) {
103- try {
104- syncPortsListWithClient(response)
105- } finally {
106- syncInProgress.set(false )
104+ // Cancel previous debounce job if exists
105+ debounceJob?.cancel()
106+
107+ // Create new debounce job
108+ debounceJob = runJob(lifetime) {
109+ delay(300 ) // 300ms debounce delay
110+ try {
111+ if (syncInProgress.compareAndSet(false , true )) {
112+ try {
113+ syncPortsListWithClient(response)
114+ } finally {
115+ syncInProgress.set(false )
116+ }
117+ } else {
118+ thisLogger().debug(" gitpod: Sync already in progress, skipping update" )
107119 }
108- } else {
109- thisLogger().debug( " gitpod: Sync already in progress, skipping update " )
120+ } finally {
121+ debounceJob = null
110122 }
111123 }
112124 }
@@ -145,48 +157,55 @@ abstract class AbstractGitpodPortForwardingService : GitpodPortForwardingService
145157 val portsNumbersFromNonServedPorts = portsList.filter { ! it.served }.map { it.localPort }
146158
147159 // Clean up unused port lifetimes
148- val allCurrentPorts = perClientPortForwardingManager.getPorts()
149160 val allPortsToKeep = mutableSetOf<Int >()
150161
151- // Find ports that need to start forwarding
152162 val servedPortsToStartForwarding = servedPorts.filter {
153163 perClientPortForwardingManager.getPorts(it.localPort).none { p -> p.labels.contains(FORWARDED_PORT_LABEL ) }
154164 }
155165
156- // Find ports that need to start exposing on client
157166 val exposedPortsToStartExposingOnClient = exposedPorts.filter {
158167 perClientPortForwardingManager.getPorts(it.localPort).none { p -> p.labels.contains(EXPOSED_PORT_LABEL ) }
159168 }
160169
161- // Find ports that need to stop forwarding
162170 val forwardedPortsToStopForwarding = perClientPortForwardingManager.getPorts(FORWARDED_PORT_LABEL )
163171 .map { it.hostPortNumber }
164172 .filter { portsNumbersFromNonServedPorts.contains(it) || ! portsNumbersFromPortsList.contains(it) }
165173
166- // Find ports that need to stop exposing on client
167174 val exposedPortsToStopExposingOnClient = perClientPortForwardingManager.getPorts(EXPOSED_PORT_LABEL )
168175 .map { it.hostPortNumber }
169176 .filter { portsNumbersFromNonServedPorts.contains(it) || ! portsNumbersFromPortsList.contains(it) }
170177
171- forwardedPortsToStopForwarding.forEach { stopForwarding(it) }
172- exposedPortsToStopExposingOnClient.forEach { stopExposingOnClient(it) }
178+ // Process port changes in background
179+ runJob(lifetime) {
180+ try {
181+ // Stop unnecessary ports first
182+ forwardedPortsToStopForwarding.forEach { stopForwarding(it) }
183+ exposedPortsToStopExposingOnClient.forEach { stopExposingOnClient(it) }
184+
185+ // Start necessary ports
186+ servedPortsToStartForwarding.forEach {
187+ startForwarding(it)
188+ allPortsToKeep.add(it.localPort)
189+ }
173190
174- servedPortsToStartForwarding .forEach {
175- startForwarding (it)
176- allPortsToKeep.add(it.localPort)
177- }
191+ exposedPortsToStartExposingOnClient .forEach {
192+ startExposingOnClient (it)
193+ allPortsToKeep.add(it.localPort)
194+ }
178195
179- exposedPortsToStartExposingOnClient.forEach {
180- startExposingOnClient(it)
181- allPortsToKeep.add(it.localPort)
182- }
196+ // Update presentation for all ports
197+ application.invokeLater {
198+ portsList.forEach {
199+ updatePortsPresentation(it)
200+ allPortsToKeep.add(it.localPort)
201+ }
202+ }
183203
184- portsList.forEach {
185- updatePortsPresentation(it)
186- allPortsToKeep.add(it.localPort)
204+ cleanupUnusedLifetimes(allPortsToKeep)
205+ } catch (e: Exception ) {
206+ thisLogger().error(" gitpod: Error during port synchronization" , e)
207+ }
187208 }
188-
189- cleanupUnusedLifetimes(allPortsToKeep)
190209 }
191210
192211 private fun cleanupUnusedLifetimes (portsToKeep : Set <Int >) {
0 commit comments