File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -242,6 +242,10 @@ const generateSnapshotDescription = async (deviceId, target) => {
242242 } )
243243}
244244
245+ const getDeviceEditorProxy = async ( editorUrl ) => {
246+ return client . get ( editorUrl )
247+ }
248+
245249export default {
246250 create,
247251 getDevice,
@@ -266,5 +270,6 @@ export default {
266270 suspendDevice,
267271 restartDevice,
268272 startDevice,
269- generateSnapshotDescription
273+ generateSnapshotDescription,
274+ getDeviceEditorProxy
270275}
Original file line number Diff line number Diff line change @@ -118,9 +118,15 @@ export function useDeviceHelper () {
118118 if ( shouldStartPolling ) { startPolling ( ) }
119119 }
120120
121- async function fetchDevice ( deviceId = null ) {
121+ async function fetchDevice ( deviceId = null , shouldSetDevice = true ) {
122122 try {
123- device . value = await deviceApi . getDevice ( deviceId || device . value ?. id )
123+ const response = await deviceApi . getDevice ( deviceId || device . value ?. id )
124+
125+ if ( shouldSetDevice ) {
126+ device . value = response
127+ }
128+
129+ return response
124130 } catch ( err ) {
125131 if ( err . status === 403 ) {
126132 stopPolling ( )
@@ -149,6 +155,14 @@ export function useDeviceHelper () {
149155 } )
150156 }
151157
158+ async function getDeviceEditorProxy ( device ) {
159+ if ( device . editor . url ) {
160+ return deviceApi . getDeviceEditorProxy ( device . editor . url )
161+ }
162+
163+ return Promise . reject ( Error ( 'editor url unavailable' ) )
164+ }
165+
152166 return {
153167 agentSupportsDeviceAccess,
154168 agentSupportsActions,
@@ -162,6 +176,7 @@ export function useDeviceHelper () {
162176 resumePolling,
163177 restartDevice,
164178 fetchDevice,
165- showDeleteDialog
179+ showDeleteDialog,
180+ getDeviceEditorProxy
166181 }
167182}
Original file line number Diff line number Diff line change @@ -129,7 +129,8 @@ export default {
129129 startPolling ,
130130 stopPolling ,
131131 resumePolling ,
132- pausePolling
132+ pausePolling ,
133+ getDeviceEditorProxy
133134 } = useDeviceHelper ()
134135
135136 return {
@@ -157,7 +158,8 @@ export default {
157158 stopPolling,
158159 resumePolling,
159160 pausePolling,
160- showDeleteDeviceDialog
161+ showDeleteDeviceDialog,
162+ getDeviceEditorProxy
161163 }
162164 },
163165 computed: {
@@ -312,7 +314,32 @@ export default {
312314 methods: {
313315 ... mapActions (' context' , { setContextDevice: ' setDevice' }),
314316 loadDevice : async function () {
315- await this .fetchDevice (this .$route .params .id )
317+ let tries = 0
318+ let device = await this .fetchDevice (this .$route .params .id , false )
319+
320+ // When running multiple replicas of the forge app, the affinity token may be missing if the request is routed to a
321+ // backend endpoint that didn't initiate the tunnel. If we receive a 502 from the device editor proxy,
322+ // we retry the editor API call until the correct affinity token is acquired (200/302).
323+ while (tries <= 5 ) {
324+ try {
325+ await this .getDeviceEditorProxy (device)
326+ break
327+ } catch (e) {
328+ if (e? .response ? .status === 502 ) {
329+ tries += 1
330+
331+ // 1s interval timeout between tries
332+ await new Promise (resolve => setTimeout (resolve, 1000 ))
333+
334+ device = await this .fetchDevice (this .$route .params .id , false )
335+ continue
336+ }
337+
338+ break
339+ }
340+ }
341+
342+ this .device = device
316343 await this .$store .dispatch (' account/setTeam' , this .device .team .slug )
317344 },
318345 showConfirmDeleteDialog () {
You can’t perform that action at this time.
0 commit comments