<!-- 
RSS generated by JIRA (1001.0.0-SNAPSHOT#100246-sha1:7a5c50119eb0633d306e14180817ddef5e80c75d) at Thu Feb 08 23:17:39 UTC 2024

It is possible to restrict the fields that are returned in this document by specifying the 'field' parameter in your request.
For example, to request only the issue key and summary add field=key&field=summary to the URL of your request.
-->
<rss version="0.92" >
<channel>
    <title>FOLIO Jira</title>
    <link>https://folio-org.atlassian.net</link>
    <description>This file is an XML representation of an issue</description>
    <language>en-us</language>    <build-info>
        <version>1001.0.0-SNAPSHOT</version>
        <build-number>100246</build-number>
        <build-date>07-02-2024</build-date>
    </build-info>

<item>
            <title>[FOLIO-2028] SPIKE: how to handle update conflicts?</title>
                <link>https://folio-org.atlassian.net/browse/FOLIO-2028</link>
                <project id="10290" key="FOLIO">FOLIO</project>
                    <description>&lt;p&gt;&lt;b&gt;Problem statement&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;In FOLIO, most storage modules follow the &quot;last writer wins&quot; strategy for handling record updates. From the end-user perspective this may lead to a situation when a stale record (older version of a record) previously loaded into the UI overrides a more recent version of the record on the server. Hence relevant updates may get lost in the process.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Possible solution&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Handling of updates in FOLIO should rely on more explicit semantics, both in the storage (backend) APIs and the way it is communicated to the user through the UI.&lt;/p&gt;

&lt;p&gt;From the storage and API perspective there are two major strategies for handling conflicting updates:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;b&gt;optimistic locking&lt;/b&gt; &amp;#8211; each record state is marked with a &quot;version number&quot; (or a timestamp, hash, etc) which is returned to the client along with the record. The client includes the version number during the update and the server checks that the version hasn&apos;t changed before it writes the record back. If the record is dirty (version doesn&apos;t match) the update is aborted. In practice for a REST API (typical FOLIO uses case) this means using ETag with a combination of If-Match conditional request and 412 (precondition failed) and 409 (conflict) error codes.&lt;/li&gt;
&lt;/ul&gt;


&lt;ul&gt;
	&lt;li&gt;&lt;b&gt;pessimistic locking&lt;/b&gt; &amp;#8211; the record being updated is &quot;locked&quot; until the client completes the update. This means no concurrent updates are possible and ensures the state between the client and server is consistent. It can, however, lead to contention issues and care must be taken to avoid deadlock situation. In practice, this strategy require an explicit &quot;locking API&quot; exposed to client (UI) &amp;#8211; the client will need to request and release lock for any record update explicitly.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In general, &lt;em&gt;optimistic locking&lt;/em&gt; is used when the risk of collisions (updates to the same record) is low and when the lock granularity is high ((ie duration of any given update is short). The opposite is true for the &lt;em&gt;pessimistic locking&lt;/em&gt; strategy.&lt;/p&gt;

&lt;p&gt;Also, the impact on the user experience should be taken into account when selecting the appropriate strategy:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;OL means that in certain situations the update operation will fail which needs to be communicated to the user, The UI should then allow the user to choose the next step, e.g by refreshing the state of the record in the browser and re-applying original changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;ul&gt;
	&lt;li&gt;PL means that a particular client (browser) owns an exclusive lock to perform &lt;b&gt;any&lt;/b&gt; updates to the record. To avoid contention issues, the lock should include an automatic timeout after whic the lock is automatically released &amp;#8211; this should be communicated to the user e.g in form of a timer.&lt;/li&gt;
&lt;/ul&gt;
</description>
                <environment></environment>
        <key id="81246">FOLIO-2028</key>
            <summary>SPIKE: how to handle update conflicts?</summary>
                <type id="10003" iconUrl="https://folio-org.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10318?size=medium">Task</type>
                                            <priority id="10002" iconUrl="https://dev.folio.org/assets/jira-priority/jira-p3.svg">P3</priority>
                        <status id="6" iconUrl="https://folio-org.atlassian.net/images/icons/statuses/closed.png" description="The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.">Closed</status>
                    <statusCategory id="3" key="done" colorName="green"/>
                                    <resolution id="10003">Done</resolution>
                                                        <assignee accountid="557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d">Jakub Skoczen</assignee>
                                                                <reporter accountid="557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d">Jakub Skoczen</reporter>
                                    <labels>
                            <label>platform-backlog</label>
                    </labels>
                <created>Mon, 20 May 2019 10:11:52 +0000</created>
                <updated>Mon, 12 Apr 2021 09:20:15 +0000</updated>
                            <resolved>Mon, 12 Apr 2021 09:20:15 +0000</resolved>
                                                                        <due></due>
                            <votes>0</votes>
                                    <watches>6</watches>
                                                                <comments>
                                                            <comment id="194478" author="712020:56d00f8b-0951-4897-ba61-10c9f41739d5" created="Fri, 24 May 2019 13:18:14 +0000"  >&lt;p&gt;Both technicians and librarians from Leipzig prefer the optimistic looking approach. Since we cannot use the system productively without a solution (end 2019), I would like to encourage the decision making process. Does it make sense to discuss this at the Product Council since it&apos;s an overarching issue? What do you think, &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=5af5ed55244bc90a106063c7&quot; class=&quot;user-hover&quot; rel=&quot;5af5ed55244bc90a106063c7&quot; data-account-id=&quot;5af5ed55244bc90a106063c7&quot; accountid=&quot;5af5ed55244bc90a106063c7&quot; rel=&quot;noreferrer&quot;&gt;Cate Boerema&lt;/a&gt; ? I know there is a lot of other things.&lt;/p&gt;</comment>
                                                            <comment id="194495" author="5af5ed55244bc90a106063c7" created="Wed, 5 Jun 2019 15:47:24 +0000"  >&lt;p&gt;Hi &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=712020%3A56d00f8b-0951-4897-ba61-10c9f41739d5&quot; class=&quot;user-hover&quot; rel=&quot;712020:56d00f8b-0951-4897-ba61-10c9f41739d5&quot; data-account-id=&quot;712020:56d00f8b-0951-4897-ba61-10c9f41739d5&quot; accountid=&quot;712020:56d00f8b-0951-4897-ba61-10c9f41739d5&quot; rel=&quot;noreferrer&quot;&gt;Bj&#246;rn Muschall&lt;/a&gt;.  In talking to &lt;a href=&quot;https://folio-org.atlassian.net/secure/ViewProfile.jspa?accountId=557058%3Ab8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; class=&quot;user-hover&quot; rel=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; data-account-id=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; accountid=&quot;557058:b8e64633-1f7c-402d-9caf-9959a5ba5d0d&quot; rel=&quot;noreferrer&quot;&gt;Jakub Skoczen&lt;/a&gt;, it seems like OL is more commonly used, more user friendly and technically simpler.  Given that, Jakub and I think we probably ought to just pursue the OL approach. &lt;/p&gt;

&lt;p&gt;If we pursue this, it could be phased as follows:&lt;br/&gt;
1. Implement OL and, when there&apos;s a conflict, give users two choices: &quot;update anyway&quot; or &quot;reload page&quot;.  This isn&apos;t a perfect solution but it is probably better than what we have now.  During this phase, our recommendation to users would be to reload the page and reapply their changes so as not to lose other updates.&lt;br/&gt;
2. Provide a third option to users when there is a conflict: &quot;merge&quot;.  We&apos;d need to decide what that option would look like (there might be some UI for viewing conflicts and deciding which version to take.  We&apos;d need UX input on this, of course, but there are models out there for how this could work (e.g. GitHub)&lt;/p&gt;

&lt;p&gt;Alternatively, we could consider implementing partial updates (PATCH) and record history.  This is what JIRA seems to do.  When there is a conflict, JIRA silently overrides (so it basically behaves like FOLIO does today) BUT the issue is mitigated by the fact that it retains update history so you can revert pretty easily (there&apos;s no revert button, but you can manually reapply).  JIRA also has inline (field-based) editing which reduces the likelihood of conflicts.&lt;/p&gt;

&lt;p&gt;Thoughts?&lt;/p&gt;</comment>
                                                            <comment id="194506" author="5ee89462f7aa140abd82d11d" created="Thu, 6 Jun 2019 07:56:28 +0000"  >&lt;p&gt;RMB supports updating only a specific field:&lt;br/&gt;
&lt;a href=&quot;https://github.com/folio-org/raml-module-builder/blob/v24.0.0/domain-models-runtime/src/main/java/org/folio/rest/persist/PostgresClient.java#L1100-L1176&quot; class=&quot;external-link&quot; rel=&quot;nofollow noreferrer&quot;&gt;https://github.com/folio-org/raml-module-builder/blob/v24.0.0/domain-models-runtime/src/main/java/org/folio/rest/persist/PostgresClient.java#L1100-L1176&lt;/a&gt;&lt;br/&gt;
This requires a special API endpoint, though. There exists no API endpoint that makes use of this single field update capability.&lt;/p&gt;</comment>
                    </comments>
                <issuelinks>
                            <issuelinktype id="10001">
                    <name>Cloners</name>
                                                                <inwardlinks description="is cloned by">
                                        <issuelink>
            <issuekey id="11061">UXPROD-1752</issuekey>
        </issuelink>
                            </inwardlinks>
                                    </issuelinktype>
                            <issuelinktype id="10003">
                    <name>Relates</name>
                                                                <inwardlinks description="relates to">
                                        <issuelink>
            <issuekey id="79654">FOLIO-2027</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="56686">RMB-688</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="38351">DEBT-1</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="56272">MODINVSTOR-713</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="57414">RMB-719</issuekey>
        </issuelink>
            <issuelink>
            <issuekey id="57419">RMB-727</issuekey>
        </issuelink>
                            </inwardlinks>
                                    </issuelinktype>
                    </issuelinks>
                <attachments>
                    </attachments>
                <subtasks>
                    </subtasks>
                <customfields>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                <customfield id="customfield_10000" key="com.atlassian.jira.plugins.jira-development-integration-plugin:devsummarycf">
                        <customfieldname>Development</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10057" key="com.atlassian.jira.plugin.system.customfieldtypes:select">
                        <customfieldname>Development Team</customfieldname>
                        <customfieldvalues>
                                <customfieldvalue key="10144"><![CDATA[Core: Platform]]></customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        <customfield id="customfield_10019" key="com.pyxis.greenhopper.jira:gh-lexo-rank">
                        <customfieldname>Rank</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>0|hzzqr3:</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    <customfield id="customfield_10020" key="com.pyxis.greenhopper.jira:gh-sprint">
                        <customfieldname>Sprint</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        <customfield id="customfield_10024" key="com.atlassian.jira.ext.charting:firstresponsedate">
                        <customfieldname>[CHART] Date of First Response</customfieldname>
                        <customfieldvalues>
                            <customfieldvalue>Fri, 24 May 2019 13:18:14 +0000</customfieldvalue>

                        </customfieldvalues>
                    </customfield>
                                                                <customfield id="customfield_10025" key="com.atlassian.jira.ext.charting:timeinstatus">
                        <customfieldname>[CHART] Time in Status</customfieldname>
                        <customfieldvalues>
                            
                        </customfieldvalues>
                    </customfield>
                                    </customfields>
    </item>
</channel>
</rss>