Skip to content

Commit

Permalink
LIWO-875: retry requests for getFeature (#420)
Browse files Browse the repository at this point in the history
* Retry getFeature request if the response type isn't json

* Show notifications if the retries fail

* Avoid using ?

* Return valid geojson to prevent map error

* Add some comments

* Remove unnecessary change

* Fail if any of the layers isn't available

* Fix outputFormat
  • Loading branch information
lsarni authored Jul 7, 2023
1 parent c16a226 commit 2edb362
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 17 deletions.
5 changes: 4 additions & 1 deletion src/lib/leaflet-utils/layer-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,10 @@ export function createClusterGeoJson (layer, onClick) {
const unselectedGeoJson = {
...layer.geojson
}
unselectedGeoJson.features = unselectedGeoJson.features.filter(feature => !feature.properties.selected)
if (unselectedGeoJson.features) {
unselectedGeoJson.features = unselectedGeoJson.features.filter(feature => !feature.properties.selected)
}

return L.geoJson(unselectedGeoJson, options)
}

Expand Down
69 changes: 59 additions & 10 deletions src/lib/load-geojson.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import mapConfig from '../map.config.js'
import store from '@/store'

const MAX_RETRIES = 5
const RETRY_DELAY = 1000 // Delay in milliseconds between retries

const requestOptions = ({ namespace, layer }) => ({
isActive: true,
Expand All @@ -13,7 +17,57 @@ const requestOptions = ({ namespace, layer }) => ({
maxFeatures: 3000
})

export async function loadGeojson (jsonLayer, { filteredIds = [] } = {}) {
const getFeatures = (url, jsonLayer, layerSetId, retries = 0) => {
return new Promise((resolve, reject) => {
fetch(url, { mode: 'cors' })
.then(resp => {
// Workaround for geoserver issue:
// When the request fails it returns 200 but the response is an XML with an error message
// We can detect this by checking the content-type header
if (
resp.headers.get('content-type') &&
!resp.headers.get('content-type').includes('application/json')
) {
caches.delete(url)
throw new Error('Response is not JSON')
}
return resp.json()
})
.then(geojson => {
geojson.features = geojson.features.map(feature => {
feature.properties.isControllable = !!jsonLayer.iscontrollayer
feature.properties.icon = 'default'
return feature
})

resolve(geojson)
})
.catch(error => {
if (retries < MAX_RETRIES) {
console.warn(`Retry ${retries + 1} - ${error}`)
setTimeout(
() =>
getFeatures(url, jsonLayer, layerSetId, retries + 1)
.then(resolve)
.catch(reject),
RETRY_DELAY
)
} else {
console.error(`Max retries exceeded - ${error}`)
// Show an error notification if the layer is not available
const notification = {
message: 'Probeer het over 5 tot 10 minuten opnieuw.',
type: 'error',
show: true
}
store.commit('addNotificationById', { id: layerSetId, notification })
reject(error)
}
})
})
}

export async function loadGeojson (jsonLayer, layerSetId, { filteredIds = [] } = {}) {
// fetch the geojson and add it to the layer

// no json, nothing to do
Expand All @@ -33,17 +87,12 @@ export async function loadGeojson (jsonLayer, { filteredIds = [] } = {}) {

const services = await mapConfig.getServices()
const url = `${services.STATIC_GEOSERVER_URL}?${params}${filterString}`
const result = fetch(url, { mode: 'cors' })
.then(resp => resp.json())
const result = getFeatures(url, jsonLayer, layerSetId)
.then(geojson => {
geojson.features = geojson.features.map(feature => {
feature.properties.isControllable = !!jsonLayer.iscontrollayer
feature.properties.icon = 'default'
return feature
})

return geojson
})
.catch(error => console.warn(error, jsonLayer))
.catch(error => {
console.warn(error, jsonLayer)
})
return result
}
2 changes: 1 addition & 1 deletion src/lib/load-layersets.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export async function loadLayerSetById (id, options) {
const variants = await Promise.all(
layer.variants.map(async (variant) => {
if (_.includes(['json', 'cluster'], variant.map.type)) {
const geojson = await loadGeojson(variant.map)
const geojson = await loadGeojson(variant.map, layerSet.id)
variant.map.geojson = geojson
}
return variant
Expand Down
10 changes: 5 additions & 5 deletions src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export default new Vuex.Store({
commit('setSelectedVariantIndexByBreachBandId', { selectedIndex, breachBandId })
}
},
async loadLayerSetById (state, { id }) {
async loadLayerSetById ({ commit, state }, { id }) {
// Skip if we already loaded this layerSet
if (_.has(state.layerSetsById, id)) {
return
Expand All @@ -112,15 +112,15 @@ export default new Vuex.Store({
// The layers are in a deep structure. Flatten it before building the notifications
const layers = flattenLayerSet(layerSet)

const notifications = buildLayerSetNotifications(layers)
const currentNotifications = state.notificationsById[id] || []
const notifications = [...currentNotifications, ...buildLayerSetNotifications(layers)]

// TODO: the function is called setLayerSet[s]
// but it only loads the layers of 1 layerSet, make this consistent

state.commit('setLayerSetById', { id, layerSet: layerSet })
commit('setLayerSetById', { id, layerSet: layerSet })

// TODO: why not in the view...
state.commit('setNotificationsById', { id, notifications })
commit('setNotificationsById', { id, notifications })
}

},
Expand Down

0 comments on commit 2edb362

Please sign in to comment.